Esempio n. 1
0
    def get(self, *keys, default=None, cast=None):
        ''' str ..., maybe any, maybe any -> any | DatabaseError

        retrieve a given key, if the key is not found `default` will be
        returned instead

        >>> values = db.get('nonexistant', 'index', default={})
        >>> type(values)
        dict

        >>> values = db.get('index', 'that', 'exists', cast=set)
        >>> type(values)
        set
        '''
        keys = list(keys) if keys else ['']
        result = self.query(keys, interpret=True)

        if not result:
            return default

        if cast:
            try:
                if not isinstance(result, (list, dict,)):
                    result = [result]
                return cast(result)

            except ValueError:
                raise DatabaseError(
                    'error: unable to case to ' + str(cast)) from None

        return result
Esempio n. 2
0
def _query(args, host='localhost', port=9999, interpret=False,
           close=True, sock=None):
    ''' list of str, str, int, bool, bool, bool -> any

    the real query function, all the others are wrappers

    send a query to an Apocrypha server, either returning a list of strs or
    the result of json.loads() on the result
    '''

    args = list(args)
    remote = (host, port)

    if interpret and args and args[-1] not in {'-e', '--edit'}:
        args += ['--edit']
    message = '\n'.join(args) + '\n'

    # if they didn't give us a socket create a new one
    if not sock:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect(remote)

    # send the message, get the reply using apocrypha.network calls
    write(sock, message)
    result, error = read(sock)

    if error:
        sock.close()
        sock = None
        raise DatabaseError('error: network length')
    if close:
        sock.close()

    result = list(filter(None, result.split('\n')))
    if result and result[0].startswith('error: '):
        raise DatabaseError(result[0]) from None

    if interpret:
        result = json.loads(''.join(result)) if result else None

    return result, sock
Esempio n. 3
0
    def _error(self, message: str) -> None:
        '''
        @message    description of the error that occurred
        #impure     self.output

        Send an error to the user and stop execution. In headless mode, errors
        are appended to the class.output list
        '''
        message = 'error: ' + message

        if self.headless:
            self.output += [message]
            raise DatabaseError(message + '\n')

        print(message, file=sys.stderr)
        sys.exit(1)
Esempio n. 4
0
    def remove(self, *keys, value):
        ''' str ..., str | list of str -> none | DatabaseError

        remove an element from a list, if more than one of the element exists
        in the list, only one is removed

        >>> db.set('my', 'list', value=['a', 'b', 'c'])
        >>> db.remove('my', 'list', value='b')
        '''
        keys = list(keys) if keys else ['']

        if isinstance(value, str):
            value = [value]

        if not isinstance(value, (str, list)):
            raise DatabaseError('error: {v} is not a str or list') from None

        self.query(keys + ['-'] + value)
Esempio n. 5
0
    def pop(self, *keys, cast=None):
        ''' str ... -> any | None
        '''
        keys = list(keys) if keys else ['']

        result = self.query(keys + ['--pop'])
        result = result[0] if result else None

        try:
            if result and cast:
                result = cast(result)

        except ValueError:
            raise DatabaseError(
                'error: cast {c} is not applicable to {t}'
                .format(c=cast.__name__, t=result)) from None

        return result
Esempio n. 6
0
    def set(self, *keys, value):
        ''' str ..., str | list | dict | none -> none

        set a value for a given key, creating if necessary. can be used to
        delete keys if value={}

        >>> events = {'key': 'value'}
        >>> db.set('devbot', 'events', value=events)
        >>> db.get('devbot', 'events')
        {'key': 'value'}
        '''
        keys = list(keys) if keys else ['']

        try:
            value = json.dumps(value)
            self.query(keys + ['--set', value])

        except (TypeError, ValueError):
            raise DatabaseError(
                'error: value is not JSON serializable') from None
Esempio n. 7
0
    def append(self, *keys, value):
        ''' str ..., str | list of str -> none | DatabaseError

        append an element to an apocrypha list. appending to a str creates a
        list with the original element and the new element

        >>> db.append('new key', value='hello')
        >>> type(db.get('new key'))
        str
        >>> db.append('new key', value='there')
        >>> type(db.get('new key'))
        list
        '''
        keys = list(keys) if keys else ['']

        if isinstance(value, str):
            value = [value]

        try:
            self.query(keys + ['+'] + value)

        except (TypeError, ValueError):
            raise DatabaseError('error: {v} is not a str or list') from None