<commit_before>import json, types
from .theExceptions import (CreationError, DeletionError, UpdateError, ValidationError, SchemaViolation, InvalidDocument, ArangoError)

__all__ = ["DocumentStore", "Document", "Edge"]

class DocumentStore(object):
    """Store all the data of a document in hierarchy of stores and handles validation.
    Does not store private information, these are in the document."""

    def __init__(self, collection, validators={}, initDct={}, patch=False, subStore=False, validateInit=False):
        self.store = {}
        self.patchStore = {}
        self.collection = collection
        self.validators = validators
        self.validateInit = validateInit
        self.isSubStore = subStore
        self.subStores = {}
        self.patching = patch

        self.mustValidate = False
        if not self.validateInit:
            self.set(initDct)

        for v in self.collection._validation.values():
            if v:
                self.mustValidate = True
                break

        if self.validateInit:
            self.set(initDct)
        
        self.patching = True

    def resetPatch(self):
        """reset patches"""
        self.patchStore = {}

    def getPatches(self):
        """get patches as a dictionary"""
        if not self.mustValidate:
            return self.getStore()

        res = {}
        res.update(self.patchStore)
        for k, v in self.subStores.items():
            res[k] = v.getPatches()
        
        return res
        
    def getStore(self):
        """get the inner store as dictionary"""
        res = {}
        res.update(self.store)
        for k, v in self.subStores.items():
            res[k] = v.getStore()
        return res

    def validateField(self, field):
        """Validatie a field"""
        if field not in self.validators and not self.collection._validation['allow_foreign_fields']:
            raise SchemaViolation(self.collection.__class__, field)

        if field in self.store:
            if isinstance(self.store[field], DocumentStore):
                return self[field].validate()
            
            if field in self.patchStore:
                return self.validators[field].validate(self.patchStore[field])
            else:
                try:
                    return self.validators[field].validate(self.store[field])
                except ValidationError as e:
                    raise ValidationError( "'%s' -> %s" % ( field, str(e)) )
                except AttributeError:
                    if isinstance(self.validators[field], dict) and not isinstance(self.store[field], dict):
                        raise ValueError("Validator expected a sub document for field '%s', got '%s' instead" % (field, self.store[field]) )
                    else:
                        raise
        return True

    def validate(self):
        """Validate the whole document"""
        if not self.mustValidate:
            return True

        res = {}
        for field in self.validators.keys():
            try:
                if isinstance(self.validators[field], dict) and field not in self.store:
                    self.store[field] = DocumentStore(self.collection, validators = self.validators[field], initDct = {}, subStore=True, validateInit=self.validateInit)
                self.validateField(field)
            except InvalidDocument as e:
                res.update(e.errors)
            except (ValidationError, SchemaViolation) as e:
                res[field] = str(e)

        if len(res) > 0:
            raise InvalidDocument(res)
        
        return True

    def set(self, dct):
        """Set the store using a dictionary"""
        # if not self.mustValidate:
        #     self.store = dct
        #     self.patchStore = dct
        #     return

        for field, value in dct.items():
            if field not in self.collection.arangoPrivates:
                if isinstance(value, dict):
                    if field in self.validators and isinstance(self.validators[field], dict):
                        vals = self.validators[field]
                    else:
                        vals = {}
                    self[field] = DocumentStore(self.collection, validators = vals, initDct = value, patch = self.patching, subStore=True, validateInit=self.validateInit)
                    self.subStores[field] = self.store[field]
                else:
                    self[field] = value

    def __dir__(self):
        return dir(self.getStore())

    def __len__(self):
        return len(self.store)

    def __dict__(self):
        return dict(self.store) + dict(self.patchStore)

    def __contains__(self, field):
        return field in store
        
    def __getitem__(self, field):
        """Get an element from the store"""
        if (field in self.validators) and isinstance(self.validators[field], dict) and (field not in self.store):
            self.store[field] = DocumentStore(self.collection, validators = self.validators[field], initDct = {}, patch = self.patching, subStore=True, validateInit=self.validateInit)
            self.subStores[field] = self.store[field]
            self.patchStore[field] = self.store[field]

        if self.collection._validation['allow_foreign_fields'] or self.collection.hasField(field):
            return self.store.get(field)

        try:
            return self.store[field]
        except KeyError:
            raise SchemaViolation(self.collection.__class__, field)

    def __setitem__(self, field, value):
        """Set an element in the store"""
        if (not self.collection._validation['allow_foreign_fields']) and (field not in self.validators) and (field not in self.collection.arangoPrivates):
            raise SchemaViolation(self.collection.__class__, field)
        
        if field in self.collection.arangoPrivates:
            raise ValueError("DocumentStore cannot contain private field (got %s)" % field)

        if isinstance(value, dict):
            if field in self.validators and isinstance(self.validators[field], dict):
                vals = self.validators[field]
            else:
                vals = {}
            self.store[field] = DocumentStore(self.collection, validators = vals, initDct = value, patch = self.patching, subStore=True, validateInit=self.validateInit)
            
            self.subStores[field] = self.store[field]
        else:
            self.store[field] = value

        if self.patching:
            self.patchStore[field] = self.store[field]

        if self.mustValidate and self.collection._validation['on_set']:
            self.validateField(field)

    def __delitem__(self, k):
        """removes an element from the store"""
        try:
            del(self.store[k])
        except:
            pass
    
        try:
            del(self.patchStore[k])
        except:
            pass

    def __contains__(self, k):
        """returns true or false weither the store has a key k"""
        return (k in self.store) or (k in self.validators)

    def __repr__(self):
        return "<store: %s>" % repr(self.store)

class Document(object):
    """The class that represents a document. Documents are meant to be instanciated by collections"""

    def __init__(self, collection, jsonFieldInit = None):
        if jsonFieldInit is None:
            jsonFieldInit = {}
        self.privates = ["_id", "_key", "_rev"]
        self.reset(collection, jsonFieldInit)
        self.typeName = "ArangoDoc"
        # self._store = None

    def reset(self, collection, jsonFieldInit = None):
        if not jsonFieldInit:<commit_msg>as sugested by @omerzohar we also need to delete values if they are a dict.<commit_after>import json, types
from .theExceptions import (CreationError, DeletionError, UpdateError, ValidationError, SchemaViolation, InvalidDocument, ArangoError)

__all__ = ["DocumentStore", "Document", "Edge"]

class DocumentStore(object):
    """Store all the data of a document in hierarchy of stores and handles validation.
    Does not store private information, these are in the document."""

    def __init__(self, collection, validators={}, initDct={}, patch=False, subStore=False, validateInit=False):
        self.store = {}
        self.patchStore = {}
        self.collection = collection
        self.validators = validators
        self.validateInit = validateInit
        self.isSubStore = subStore
        self.subStores = {}
        self.patching = patch

        self.mustValidate = False
        if not self.validateInit:
            self.set(initDct)

        for v in self.collection._validation.values():
            if v:
                self.mustValidate = True
                break

        if self.validateInit:
            self.set(initDct)
        
        self.patching = True

    def resetPatch(self):
        """reset patches"""
        self.patchStore = {}

    def getPatches(self):
        """get patches as a dictionary"""
        if not self.mustValidate:
            return self.getStore()

        res = {}
        res.update(self.patchStore)
        for k, v in self.subStores.items():
            res[k] = v.getPatches()
        
        return res
        
    def getStore(self):
        """get the inner store as dictionary"""
        res = {}
        res.update(self.store)
        for k, v in self.subStores.items():
            res[k] = v.getStore()
        return res

    def validateField(self, field):
        """Validatie a field"""
        if field not in self.validators and not self.collection._validation['allow_foreign_fields']:
            raise SchemaViolation(self.collection.__class__, field)

        if field in self.store:
            if isinstance(self.store[field], DocumentStore):
                return self[field].validate()
            
            if field in self.patchStore:
                return self.validators[field].validate(self.patchStore[field])
            else:
                try:
                    return self.validators[field].validate(self.store[field])
                except ValidationError as e:
                    raise ValidationError( "'%s' -> %s" % ( field, str(e)) )
                except AttributeError:
                    if isinstance(self.validators[field], dict) and not isinstance(self.store[field], dict):
                        raise ValueError("Validator expected a sub document for field '%s', got '%s' instead" % (field, self.store[field]) )
                    else:
                        raise
        return True

    def validate(self):
        """Validate the whole document"""
        if not self.mustValidate:
            return True

        res = {}
        for field in self.validators.keys():
            try:
                if isinstance(self.validators[field], dict) and field not in self.store:
                    self.store[field] = DocumentStore(self.collection, validators = self.validators[field], initDct = {}, subStore=True, validateInit=self.validateInit)
                self.validateField(field)
            except InvalidDocument as e:
                res.update(e.errors)
            except (ValidationError, SchemaViolation) as e:
                res[field] = str(e)

        if len(res) > 0:
            raise InvalidDocument(res)
        
        return True

    def set(self, dct):
        """Set the store using a dictionary"""
        # if not self.mustValidate:
        #     self.store = dct
        #     self.patchStore = dct
        #     return

        for field, value in dct.items():
            if field not in self.collection.arangoPrivates:
                if isinstance(value, dict):
                    if field in self.validators and isinstance(self.validators[field], dict):
                        vals = self.validators[field]
                    else:
                        vals = {}
                    self[field] = DocumentStore(self.collection, validators = vals, initDct = value, patch = self.patching, subStore=True, validateInit=self.validateInit)
                    self.subStores[field] = self.store[field]
                else:
                    self[field] = value

    def __dir__(self):
        return dir(self.getStore())

    def __len__(self):
        return len(self.store)

    def __dict__(self):
        return dict(self.store) + dict(self.patchStore)

    def __contains__(self, field):
        return field in store
        
    def __getitem__(self, field):
        """Get an element from the store"""
        if (field in self.validators) and isinstance(self.validators[field], dict) and (field not in self.store):
            self.store[field] = DocumentStore(self.collection, validators = self.validators[field], initDct = {}, patch = self.patching, subStore=True, validateInit=self.validateInit)
            self.subStores[field] = self.store[field]
            self.patchStore[field] = self.store[field]

        if self.collection._validation['allow_foreign_fields'] or self.collection.hasField(field):
            return self.store.get(field)

        try:
            return self.store[field]
        except KeyError:
            raise SchemaViolation(self.collection.__class__, field)

    def __setitem__(self, field, value):
        """Set an element in the store"""
        if (not self.collection._validation['allow_foreign_fields']) and (field not in self.validators) and (field not in self.collection.arangoPrivates):
            raise SchemaViolation(self.collection.__class__, field)
        
        if field in self.collection.arangoPrivates:
            raise ValueError("DocumentStore cannot contain private field (got %s)" % field)

        if isinstance(value, dict):
            if field in self.validators and isinstance(self.validators[field], dict):
                vals = self.validators[field]
            else:
                vals = {}
            self.store[field] = DocumentStore(self.collection, validators = vals, initDct = value, patch = self.patching, subStore=True, validateInit=self.validateInit)
            
            self.subStores[field] = self.store[field]
        else:
            self.store[field] = value

        if self.patching:
            self.patchStore[field] = self.store[field]

        if self.mustValidate and self.collection._validation['on_set']:
            self.validateField(field)

    def __delitem__(self, k):
        """removes an element from the store"""
        try:
            del(self.store[k])
        except:
            pass

        try:
            del(self.patchStore[k])
        except:
            pass

        try:
            del(self.subStores[k])
        except:
            pass

    def __contains__(self, k):
        """returns true or false weither the store has a key k"""
        return (k in self.store) or (k in self.validators)

    def __repr__(self):
        return "<store: %s>" % repr(self.store)

class Document(object):
    """The class that represents a document. Documents are meant to be instanciated by collections"""

    def __init__(self, collection, jsonFieldInit = None):
        if jsonFieldInit is None:
            jsonFieldInit = {}
        self.privates = ["_id", "_key", "_rev"]
        self.reset(collection, jsonFieldInit)
        self.typeName = "ArangoDoc"
        # self._store = None

    def reset(self, collection, jsonFieldInit = None):
        if not jsonFieldInit:
{'fraction_non_alphanumeric': 0.09951960529732537, 'fraction_numerical': 0.00012983640612827837, 'mean_word_length': 2.019404155233242, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, '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': '1162270', 'n_tokens_mistral': 4121, 'n_tokens_neox': 3989, 'n_words': 1111}