Пример #1
0
class ResetLinkModel:
    """Database model to store generated reset links."""
    def __init__(self):
        self.db = Database(variables['db'])

    def generate(self):
        random_string = ''.join(
            random.choice('abcdefghijklmnopqrstuvwxyz1234567890')
            for _ in range(30))
        dt = datetime.now() + timedelta(days=+1)
        dt_string = dt.strftime("%Y%m%d%H%M%S")
        reset_string = f'{random_string}-{dt_string}'
        return reset_string

    def _check_expire(self, resetlink):
        now = datetime.now()
        dt_expire_string = resetlink.split('-')[1]
        dt_expire = datetime.strptime(dt_expire_string, "%Y%m%d%H%M%S")
        return dt_expire > now

    def add(self, resetlink, email):
        self.db.data(key=resetlink, value=email)

    def get(self, resetlink):
        return self.db.data(key=resetlink)

    def exists(self, resetlink):
        if resetlink in self.db:
            return self._check_expire(resetlink)
        return False

    def delete(self, resetlink):
        self.db.delete(resetlink)
Пример #2
0
class Cache:
    """User credentials data Cache.

    Note:
        Stores user's username and password in JSON database to decrease requests count to authentication backend.
        All users password values are stored encrypted only.
        User password stores because of it can be changed anytime at authentication backend side. And this should be handled.
        Thus, credentials should be stored and validated in authentication backend every cache expiration period.
    """
    def __init__(self, expirationMinutes):
        self.expirationMinutes = expirationMinutes
        self.cache = {}
        self.validUntil = datetime.now(
            timezone('UTC')) + timedelta(minutes=self.expirationMinutes)
        self.logger = logging.getLogger(__class__.__name__)
        self.db = Database(variables['db'])
        self.cryptor = Fernet(Fernet.generate_key())

    def add(self, username, password, password_encrypted):
        if password_encrypted:
            pswd = password
        else:
            pswd = self.cryptor.encrypt(password.encode())
        self.db.data(key=username,
                     value={
                         'password':
                         pswd,
                         'ttl':
                         datetime.now(timezone('UTC')) +
                         timedelta(minutes=self.expirationMinutes)
                     })
        self.logger.debug(
            f'User cache record for username {username} has been added.')

    def get(self, username):
        return self.db.data(key=username)

    def validate(self, username, password):
        if username in self.db:
            if self.db.data(key=username)['password'] == password:
                ttl = self.db.data(key=username)['ttl']
                if ttl > datetime.now(timezone('UTC')):
                    return True
        self.logger.debug(
            f'User cache record for username {username} was not found or expired.'
        )
        self.db.delete(username)
        return False

    def decrypt(self, value):
        return self.cryptor.decrypt(value).decode()
Пример #3
0
class JsonFileStorageAdapter(StorageAdapter):
    """
    This adapter allows ChatterBot to store conversation
    data in a file in JSON format.
    """

    def __init__(self, **kwargs):
        super(JsonFileStorageAdapter, self).__init__(**kwargs)

        if not kwargs.get('silence_performance_warning', False):
            warnings.warn(
                'The JsonFileStorageAdapter is not recommended for production application environments.',
                self.UnsuitableForProductionWarning
            )

        database_path = self.kwargs.get('database', 'database.db')
        self.database = Database(database_path)

        self.adapter_supports_queries = False

    def _keys(self):
        # The value has to be cast as a list for Python 3 compatibility
        return list(self.database[0].keys())

    def count(self):
        return len(self._keys())

    def find(self, statement_text):
        values = self.database.data(key=statement_text)

        if not values:
            return None

        values['text'] = statement_text

        return self.json_to_object(values)

    def remove(self, statement_text):
        """
        Removes the statement that matches the input text.
        Removes any responses from statements if the response text matches the
        input text.
        """
        for statement in self.filter(in_response_to__contains=statement_text):
            statement.remove_response(statement_text)
            self.update(statement)

        self.database.delete(statement_text)

    def deserialize_responses(self, response_list):
        """
        Takes the list of response items and returns
        the list converted to Response objects.
        """
        proxy_statement = Statement('')

        for response in response_list:
            data = response.copy()
            text = data['text']
            del(data['text'])

            proxy_statement.add_response(
                Response(text, **data)
            )

        return proxy_statement.in_response_to

    def json_to_object(self, statement_data):
        
        # Don't modify the referenced object
        statement_data = statement_data.copy()

        # Build the objects for the response list
        statement_data['in_response_to'] = self.deserialize_responses(
            statement_data['in_response_to']
        )

        # Remove the text attribute from the values
        text = statement_data.pop('text')

        return Statement(text, **statement_data)

    def _all_kwargs_match_values(self, kwarguments, values):
        for kwarg in kwarguments:

            if '__' in kwarg:
                kwarg_parts = kwarg.split('__')

                key = kwarg_parts[0]
                identifier = kwarg_parts[1]

                if identifier == 'contains':
                    text_values = []
                    for val in values[key]:
                        text_values.append(val['text'])

                    if (kwarguments[kwarg] not in text_values) and (
                            kwarguments[kwarg] not in values[key]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        results = []

        for key in self._keys():
            values = self.database.data(key=key)

            # Add the text attribute to the values
            values['text'] = key

            if self._all_kwargs_match_values(kwargs, values):

                results.append(self.json_to_object(values))

        return results

    def update(self, statement, **kwargs):
        # Do not alter the database unless writing is enabled
        if not self.read_only:
            data = statement.serialize()

            # Remove the text key from the data
            del(data['text'])
            self.database.data(key=statement.text, value=data)

            # Make sure that an entry for each response exists
            for response_statement in statement.in_response_to:
                response = self.find(response_statement.text)
                if not response:
                    response = Statement(response_statement.text)
                    self.update(response)

        return statement

    def get_random(self):
        from random import choice

        if self.count() < 1:
            raise self.EmptyDatabaseException()

        statement = choice(self._keys())
        return self.find(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        import os

        if os.path.exists(self.database.path):
            os.remove(self.database.path)

    class UnsuitableForProductionWarning(Warning):
        pass
Пример #4
0
class JsonFileStorageAdapter(StorageAdapter):
    """
    This adapter allows ChatterBot to store conversation
    data in a file in JSON format.
    """
    def __init__(self, **kwargs):
        super(JsonFileStorageAdapter, self).__init__(**kwargs)
        database_path = self.kwargs.get('database', 'database.db')
        self.database = Database(database_path)

    def _keys(self):
        # The value has to be cast as a list for Python 3 compatibility
        return list(self.database[0].keys())

    def count(self):
        return len(self._keys())

    def find(self, statement_text):
        values = self.database.data(key=statement_text)

        if not values:
            return None

        values['text'] = statement_text

        return self.json_to_object(values)

    def remove(self, statement_text):
        """
        Removes the statement that matches the input text.
        Removes any responses from statements if the response text matches the
        input text.
        """
        for statement in self.filter(in_response_to__contains=statement_text):
            statement.remove_response(statement_text)
            self.update(statement)

        self.database.delete(statement_text)

    def deserialize_responses(self, response_list):
        """
        Takes the list of response items and returns
        the list converted to Response objects.
        """
        proxy_statement = Statement('')

        for response in response_list:
            data = response.copy()
            text = data['text']
            del (data['text'])

            proxy_statement.add_response(Response(text, **data))

        return proxy_statement.in_response_to

    def json_to_object(self, statement_data):

        # Don't modify the referenced object
        statement_data = statement_data.copy()

        # Build the objects for the response list
        statement_data['in_response_to'] = self.deserialize_responses(
            statement_data['in_response_to'])

        # Remove the text attribute from the values
        text = statement_data.pop('text')

        return Statement(text, **statement_data)

    def _all_kwargs_match_values(self, kwarguments, values):
        for kwarg in kwarguments:

            if '__' in kwarg:
                kwarg_parts = kwarg.split('__')

                key = kwarg_parts[0]
                identifier = kwarg_parts[1]

                if identifier == 'contains':
                    text_values = []
                    for val in values[key]:
                        text_values.append(val['text'])

                    if (kwarguments[kwarg]
                            not in text_values) and (kwarguments[kwarg]
                                                     not in values[key]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        results = []

        for key in self._keys():
            values = self.database.data(key=key)

            # Add the text attribute to the values
            values['text'] = key

            if self._all_kwargs_match_values(kwargs, values):

                results.append(self.json_to_object(values))

        return results

    def update(self, statement):
        # Do not alter the database unless writing is enabled
        if not self.read_only:
            data = statement.serialize()

            # Remove the text key from the data
            del (data['text'])
            self.database.data(key=statement.text, value=data)

            # Make sure that an entry for each response exists
            for response_statement in statement.in_response_to:
                response = self.find(response_statement.text)
                if not response:
                    response = Statement(response_statement.text)
                    self.update(response)

        return statement

    def get_random(self):
        from random import choice

        if self.count() < 1:
            raise self.EmptyDatabaseException()

        statement = choice(self._keys())
        return self.find(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        import os

        if os.path.exists(self.database.path):
            os.remove(self.database.path)

    class UnsuitableForProductionWarning(Warning):
        pass
Пример #5
0
class JsonDatabaseAdapter(StorageAdapter):

    def __init__(self, **kwargs):
        super(JsonDatabaseAdapter, self).__init__(**kwargs)
        database_path = self.kwargs.get("database", "database.db")
        self.database = Database(database_path)

    def _keys(self):
        # The value has to be cast as a list for Python 3 compatibility
        return list(self.database[0].keys())

    def count(self):
        return len(self._keys())

    def find(self, statement_text):
        values = self.database.data(key=statement_text)

        if not values:
            return None

        # Build the objects for the response list
        response_list = self._objectify_response_list(values["in_response_to"])
        values["in_response_to"] = response_list

        return Statement(statement_text, **values)

    def _objectify_response_list(self, response_list):
        """
        Takes the list of response items and returns the
        list converted to object versions of the responses.
        """
        in_response_to = []

        for item in response_list:
            text = item[0]
            occurrence = item[1]

            in_response_to.append(
                Response(text, occurrence=occurrence)
            )

        return in_response_to

    def _all_kwargs_match_values(self, kwarguments, values):

        for kwarg in kwarguments:

            if "__" in kwarg:
                kwarg_parts = kwarg.split("__")

                if kwarg_parts[1] == "contains":
                    text_values = []
                    for val in values[kwarg_parts[0]]:
                        text_values.append(val[0])

                    if (kwarguments[kwarg] not in text_values) and (kwarguments[kwarg] not in values[kwarg_parts[0]]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        results = []

        for key in self._keys():
            values = self.database.data(key=key)

            if self._all_kwargs_match_values(kwargs, values):

                # Build the objects for the response list
                response_list = self._objectify_response_list(values["in_response_to"])
                values["in_response_to"] = response_list

                results.append(
                    Statement(key, **values)
                )

        return results

    def update(self, statement):
        # Do not alter the database unless writing is enabled
        if not self.read_only:
            data = statement.serialize()

            # Remove the text key from the data
            del(data['text'])
            self.database.data(key=statement.text, value=data)

            # Make sure that an entry for each response is saved
            for response_statement in statement.in_response_to:
                response = self.find(response_statement.text)
                if not response:
                    response = Statement(response_statement.text)
                    self.update(response)

        return statement

    def get_random(self):
        from random import choice

        if self.count() < 1:
            raise EmptyDatabaseException()

        statement = choice(self._keys())
        return self.find(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        import os

        os.remove(self.database.path)
Пример #6
0
class JsonFileStorageAdapter(StorageAdapter):
    """
    This adapter allows ChatterBot to store conversation
    data in a file in JSON format.

    :keyword database: The path to the json file you wish to store data in.
    :type database: str

    :keyword silence_performance_warning: If set to True, the :code:`UnsuitableForProductionWarning`
                                          will not be displayed.
    :type silence_performance_warning: bool
    """

    def __init__(self, **kwargs):
        super(JsonFileStorageAdapter, self).__init__(**kwargs)
        from jsondb import Database

        if not kwargs.get('silence_performance_warning', False):
            warnings.warn(
                'The JsonFileStorageAdapter is not recommended for production environments.',
                self.UnsuitableForProductionWarning
            )

        warnings.warn(
            'The JsonFileStorageAdapter is deprecated and '
            'will be removed in ChatterBot version 0.8.',
            DeprecationWarning
        )

        database_path = self.kwargs.get('database', 'database.db')
        self.database = Database(database_path)

        self.adapter_supports_queries = False

    def _keys(self):
        # The value has to be cast as a list for Python 3 compatibility
        return list(self.database[0].keys())

    def count(self):
        return len(self._keys())

    def find(self, statement_text):
        values = self.database.data(key=statement_text)

        if not values:
            return None

        values['text'] = statement_text

        return self.json_to_object(values)

    def remove(self, statement_text):
        """
        Removes the statement that matches the input text.
        Removes any responses from statements if the response text matches the
        input text.
        """
        for statement in self.filter(in_response_to__contains=statement_text):
            statement.remove_response(statement_text)
            self.update(statement)

        self.database.delete(statement_text)

    def deserialize_responses(self, response_list):
        """
        Takes the list of response items and returns
        the list converted to Response objects.
        """
        proxy_statement = self.Statement('')

        for response in response_list:
            data = response.copy()
            text = data['text']
            del data['text']

            proxy_statement.add_response(
                Response(text, **data)
            )

        return proxy_statement.in_response_to

    def json_to_object(self, statement_data):
        """
        Converts a dictionary-like object to a Statement object.
        """

        # Don't modify the referenced object
        statement_data = statement_data.copy()

        # Build the objects for the response list
        statement_data['in_response_to'] = self.deserialize_responses(
            statement_data['in_response_to']
        )

        # Remove the text attribute from the values
        text = statement_data.pop('text')

        return self.Statement(text, **statement_data)

    def _all_kwargs_match_values(self, kwarguments, values):
        for kwarg in kwarguments:

            if '__' in kwarg:
                kwarg_parts = kwarg.split('__')

                key = kwarg_parts[0]
                identifier = kwarg_parts[1]

                if identifier == 'contains':
                    text_values = []
                    for val in values[key]:
                        text_values.append(val['text'])

                    if (kwarguments[kwarg] not in text_values) and (
                            kwarguments[kwarg] not in values[key]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        from operator import attrgetter

        results = []

        order_by = kwargs.pop('order_by', None)

        for key in self._keys():
            values = self.database.data(key=key)

            # Add the text attribute to the values
            values['text'] = key

            if self._all_kwargs_match_values(kwargs, values):
                results.append(self.json_to_object(values))

        if order_by:

            # Sort so that newer datetimes appear first
            is_reverse = order_by == 'created_at'

            # Do an in place sort of the results
            results.sort(key=attrgetter(order_by), reverse=is_reverse)

        return results

    def update(self, statement):
        """
        Update a statement in the database.
        """
        data = statement.serialize()

        # Remove the text key from the data
        del data['text']
        self.database.data(key=statement.text, value=data)

        # Make sure that an entry for each response exists
        for response_statement in statement.in_response_to:
            response = self.find(response_statement.text)
            if not response:
                response = self.Statement(response_statement.text)
                self.update(response)

        return statement

    def get_random(self):
        from random import choice

        if self.count() < 1:
            raise self.EmptyDatabaseException()

        statement = choice(self._keys())
        return self.find(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        self.database.drop()

    class UnsuitableForProductionWarning(Warning):
        """
        The json file storage adapter will display an :code:`UnsuitableForProductionWarning`
        when it is initialized because it is not intended for use in large scale production
        applications. You can silence this warning by setting
        :code:`silence_performance_warning=True` when initializing the adapter.
        """
        pass
Пример #7
0
class JsonDatabaseAdapter(StorageAdapter):
    """
    The JsonDatabaseAdapter is an interface that allows ChatterBot
    to store the conversation as a Json-encoded file.
    """
    def __init__(self, **kwargs):
        super(JsonDatabaseAdapter, self).__init__(**kwargs)

        database_path = self.kwargs.get("database", "database.db")
        self.database = Database(database_path)

    def _keys(self):
        # The value has to be cast as a list for Python 3 compatibility
        return list(self.database[0].keys())

    def count(self):
        return len(self._keys())

    def find(self, statement_text):
        values = self.database.data(key=statement_text)

        if not values:
            return None

        # Build the objects for the response list
        response_list = self.deserialize_responses(values["in_response_to"])
        values["in_response_to"] = response_list

        return Statement(statement_text, **values)

    def remove(self, statement_text):
        """
        Removes the statement that matches the input text.
        Removes any responses from statements if the response text matches the
        input text.
        """
        for statement in self.filter(in_response_to__contains=statement_text):
            statement.remove_response(statement_text)
            self.update(statement)

        self.database.delete(statement_text)

    def deserialize_responses(self, response_list):
        """
        Takes the list of response items and returns the
        list converted to object versions of the responses.
        """
        in_response_to = []

        for response in response_list:
            text = response["text"]
            del (response["text"])

            in_response_to.append(Response(text, **response))

        return in_response_to

    def _all_kwargs_match_values(self, kwarguments, values):
        for kwarg in kwarguments:

            if "__" in kwarg:
                kwarg_parts = kwarg.split("__")

                key = kwarg_parts[0]
                identifier = kwarg_parts[1]

                if identifier == "contains":
                    text_values = []
                    for val in values[key]:
                        text_values.append(val["text"])

                    if (kwarguments[kwarg]
                            not in text_values) and (kwarguments[kwarg]
                                                     not in values[key]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        results = []

        for key in self._keys():
            values = self.database.data(key=key)

            # Add the text attribute to the values
            values["text"] = key

            if self._all_kwargs_match_values(kwargs, values):

                # Build the objects for the response list
                in_response_to = values["in_response_to"]
                response_list = self.deserialize_responses(in_response_to)
                values["in_response_to"] = response_list

                # Remove the text attribute from the values
                text = values.pop("text")

                results.append(Statement(text, **values))

        return results

    def update(self, statement):
        # Do not alter the database unless writing is enabled
        if not self.read_only:
            data = statement.serialize()

            # Remove the text key from the data
            del (data['text'])
            self.database.data(key=statement.text, value=data)

            # Make sure that an entry for each response exists
            for response_statement in statement.in_response_to:
                response = self.find(response_statement.text)
                if not response:
                    response = Statement(response_statement.text)
                    self.update(response)

        return statement

    def get_random(self):
        from random import choice

        if self.count() < 1:
            raise EmptyDatabaseException()

        statement = choice(self._keys())
        return self.find(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        import os

        if os.path.exists(self.database.path):
            os.remove(self.database.path)
Пример #8
0
class JsonDatabaseAdapter(StorageAdapter):
    """
    The JsonDatabaseAdapter is an interface that allows ChatterBot
    to store the conversation as a Json-encoded file.
    """

    def __init__(self, **kwargs):
        super(JsonDatabaseAdapter, self).__init__(**kwargs)

        database_path = self.kwargs.get("database", "database.db")
        self.database = Database(database_path)

    def _keys(self):
        # The value has to be cast as a list for Python 3 compatibility
        return list(self.database[0].keys())

    def count(self):
        return len(self._keys())

    def find(self, statement_text):
        values = self.database.data(key=statement_text)

        if not values:
            return None

        # Build the objects for the response list
        response_list = self.deserialize_responses(values["in_response_to"])
        values["in_response_to"] = response_list

        return Statement(statement_text, **values)

    def remove(self, statement_text):
        """
        Removes the statement that matches the input text.
        Removes any responses from statements if the response text matches the
        input text.
        """
        for statement in self.filter(in_response_to__contains=statement_text):
            statement.remove_response(statement_text)
            self.update(statement)

        self.database.delete(statement_text)

    def deserialize_responses(self, response_list):
        """
        Takes the list of response items and returns the
        list converted to object versions of the responses.
        """
        in_response_to = []

        for response in response_list:
            text = response["text"]
            del(response["text"])

            in_response_to.append(
                Response(text, **response)
            )

        return in_response_to

    def _all_kwargs_match_values(self, kwarguments, values):
        for kwarg in kwarguments:

            if "__" in kwarg:
                kwarg_parts = kwarg.split("__")

                key = kwarg_parts[0]
                identifier = kwarg_parts[1]

                if identifier == "contains":
                    text_values = []
                    for val in values[key]:
                        text_values.append(val["text"])

                    if (kwarguments[kwarg] not in text_values) and (
                            kwarguments[kwarg] not in values[key]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        results = []

        for key in self._keys():
            values = self.database.data(key=key)

            # Add the text attribute to the values
            values["text"] = key

            if self._all_kwargs_match_values(kwargs, values):

                # Build the objects for the response list
                in_response_to = values["in_response_to"]
                response_list = self.deserialize_responses(in_response_to)
                values["in_response_to"] = response_list

                # Remove the text attribute from the values
                text = values.pop("text")

                results.append(
                    Statement(text, **values)
                )

        return results

    def update(self, statement):
        # Do not alter the database unless writing is enabled
        if not self.read_only:
            data = statement.serialize()

            # Remove the text key from the data
            del(data['text'])
            self.database.data(key=statement.text, value=data)

            # Make sure that an entry for each response exists
            for response_statement in statement.in_response_to:
                response = self.find(response_statement.text)
                if not response:
                    response = Statement(response_statement.text)
                    self.update(response)

        return statement

    def get_random(self):
        from random import choice

        if self.count() < 1:
            raise self.EmptyDatabaseException()

        statement = choice(self._keys())
        return self.find(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        import os

        if os.path.exists(self.database.path):
            os.remove(self.database.path)
Пример #9
0
class JsonDatabaseAdapter(StorageAdapter):
    """
    The JsonDatabaseAdapter is an interface that allows ChatterBot
    to store the conversation as a Json-encoded file.
    """

    def create_user_storage(self, **kwargs):
        _kwargs = self.kwargs.copy()
        _kwargs.update(kwargs)
        return UserJsonDatabaseAdapter(**_kwargs)

    def __init__(self, **kwargs):
        super(JsonDatabaseAdapter, self).__init__(**kwargs)

        if "database_path" not in self.kwargs:
            raise ValueError(_("You need to specify database path"))
        database_path = self.kwargs.get("database_path")
        from jsondb import Database
        self.database = Database(database_path)

    def _keys(self, filter_func=None):
        keys = self.database[0].keys()
        return list(filter(filter_func, keys) if callable(filter_func) else keys)

    def count(self, filter_func=None):
        return len(self._keys(filter_func))

    def get(self, statement_text, default=None):
        values = self.database.data(key=statement_text)

        if not values:
            return default

        return values

    def remove(self, statement_text):
        self.database.delete(statement_text)

    def _all_kwargs_match_values(self, kwarguments, values):
        for kwarg in kwarguments:

            if "__" in kwarg:
                kwarg_parts = kwarg.split("__")

                key = kwarg_parts[0]
                identifier = kwarg_parts[1]

                if identifier == "contains":
                    text_values = []
                    for val in values[key]:
                        text_values.append(val["text"])

                    if (kwarguments[kwarg] not in text_values) and (
                                kwarguments[kwarg] not in values[key]):
                        return False

            if kwarg in values:
                if values[kwarg] != kwarguments[kwarg]:
                    return False

        return True

    def filter(self, filter_func=None, **kwargs):
        """
        Returns a list of statements in the database
        that match the parameters specified.
        """
        results = []

        for key in self._keys(filter_func):
            values = self.database.data(key=key)

            if self._all_kwargs_match_values(kwargs, values):
                results.append(values)

        if not results:
            return None

        return results

    def update(self, key, value):
        # Do not alter the database unless writing is enabled
        if not self.read_only:
            self.database.data(key=key, value=value)
            return True
        return False

    def get_random(self, key):
        from random import choice

        if self.count() < 1:
            raise self.EmptyDatabaseException()

        statement = choice(self._keys())
        return self.get(statement)

    def drop(self):
        """
        Remove the json file database completely.
        """
        import os

        if os.path.exists(self.database.path):
            os.remove(self.database.path)