pyorient/constants.py
DB_SIZE_OP                 = chr(8)
pyorient/constants.py
DB_CREATE_OP               = chr(4)
pyorient/constants.py
SUPPORTED_PROTOCOL = 36
pyorient/constants.py
FIELD_BYTES = {"type": BYTES, "bytes": 4, "struct": None}
pyorient/constants.py
FIELD_BOOLEAN = {"type": BOOLEAN, "bytes": 1, "struct": None}
pyorient/constants.py
STORAGE_TYPE_PLOCAL = 'plocal'
pyorient/constants.py
VERSION = "1.5.5"
pyorient/constants.py
STORAGE_TYPE_LOCAL  = 'local'
pyorient/constants.py
FIELD_INT = {"type": INT, "bytes": 4, "struct": None}
pyorient/constants.py
DB_CLOSE_OP                = chr(5)
pyorient/constants.py
FIELD_STRING = {"type": STRING, "bytes": 4, "struct": None}
pyorient/constants.py
DB_EXIST_OP                = chr(6)
pyorient/constants.py
DB_RELOAD_OP               = chr(73)
pyorient/constants.py
DB_COUNT_RECORDS_OP        = chr(9)
pyorient/otypes.py
class OrientNode(object):
    def __init__(self, node_dict=None):
        """
        Represent a server node in a multi clusered configuration

        TODO: extends this object with different listeners if we're going to support in the driver an abstarction of the HTTP protocol, for now we are not interested in that

        :param node_dict: dict with starting configs (usaully from a db_open, db_reload record response)
        """
        #: node name
        self.name = None

        #: node is
        self.id = None

        #: datetime object the node was started
        self.started_on = None

        #: binary listener host
        self.host = None

        #: binary lister port
        self.port = None

        if node_dict is not None:
            self._parse_dict(node_dict)

    def _parse_dict(self, node_dict):
        self.id = node_dict['id']
        self.name = node_dict['name']
        self.started_on = node_dict['startedOn']
        listener = None
        for l in node_dict['listeners']:
            if l['protocol'] == 'ONetworkProtocolBinary':
                listener = l
                break

        if listener:
            listen = listener['listen'].split(':')
            self.host = listen[0]
            self.port = listen[1]

    def __str__(self):
        return self.name
pyorient/otypes.py
class OrientVersion(object):

    def __init__(self, release):
        """
        Object representing Orient db release Version

        :param release: String release
        """

        #: string full OrientDB release
        self.release = release

        #: Major version
        self.major = None

        #: Minor version
        self.minor = None

        #: build number
        self.build = None

        #: string build version
        self.subversion = None

        self._parse_version(release)

    def _parse_version( self, string_release ):

        import re
        if not isinstance(string_release, str):
            string_release = string_release.decode()

        try:
            version_info = string_release.split( "." )
            self.major = version_info[0]
            self.minor = version_info[1]
            self.build = version_info[2]
        except IndexError:
            pass

        regx = re.match('.*([0-9]+).*', self.major )
        self.major = regx.group(1)

        try:
            _temp = self.minor.split( "-" )
            self.minor = _temp[0]
            self.subversion = _temp[1]
        except IndexError:
            pass

        try:
            regx = re.match( '([0-9]+)[\.\- ]*(.*)', self.build )
            self.build = regx.group(1)
            self.subversion = regx.group(2)
        except TypeError:
            pass

        self.major = int( self.major )
        self.minor = int( self.minor )
        self.build = 0 if self.build is None else int( self.build )
        self.subversion = '' if self.subversion is None else str( self.subversion )

    def __str__(self):
        return self.release
pyorient/constants.py
DB_TYPE_DOCUMENT    = 'document'
pyorient/constants.py
FIELD_SHORT = {"type": SHORT, "bytes": 2, "struct": None}
pyorient/otypes.py
class OrientRecord(object):
    """
    Object that represent an Orient Document / Record

    """
    oRecordData = property(lambda self: self.__o_storage)

    def __str__(self):
        rep = ""
        if self.__o_storage:
            rep = str( self.__o_storage )
        if self.__o_class is not None:
            rep = "'@" + str(self.__o_class) + "':" + rep + ""
        if self.__version is not None:
            rep = rep + ",'version':" + str(self.__version)
        if self.__rid is not None:
            rep = rep + ",'rid':'" + str(self.__rid) + "'"
        return '{' + rep + '}'

    @staticmethod
    def addslashes(string):
        l = [ "\\", '"', "'", "\0", ]
        for i in l:
            if i in string:
                string = string.replace( i, '\\' + i )
        return string

    def __init__(self, content=None):

        self.__rid = None
        self.__version = None
        self.__o_class = None
        self.__o_storage = {}

        if not content:
            content = {}
        for key in content.keys():
            if key == '__rid':  # Ex: select @rid, field from v_class
                self.__rid = content[ key ]
                # self.__rid = OrientRecordLink( content[ key ][ 1: ] )
            elif key == '__version':  # Ex: select @rid, @version from v_class
                self.__version = content[key]
            elif key == '__o_class':
                self.__o_class = content[ key ]
            elif key[0:1] == '@':
                # special case dict
                # { '@my_class': { 'accommodation': 'hotel' } }
                self.__o_class = key[1:]
                for _key, _value in content[key].items():
                    if isinstance(_value, basestring):
                        self.__o_storage[_key] = self.addslashes( _value )
                    else:
                        self.__o_storage[_key] = _value
            elif key == '__o_storage':
                self.__o_storage = content[key]
            else:
                self.__o_storage[key] = content[key]

    def _set_keys(self, content=dict):
        for key in content.keys():
                self._set_keys( content[key] )

    @property
    def _in(self):
        try:
            return self.__o_storage['in']
        except KeyError:
            return None

    @property
    def _out(self):
        try:
            return self.__o_storage['out']
        except KeyError:
            return None

    @property
    def _rid(self):
        return self.__rid

    @property
    def _version(self):
        return self.__version

    @property
    def _class(self):
        return self.__o_class

    def update(self, **kwargs):
        self.__rid = kwargs.get('__rid', None)
        self.__version = kwargs.get('__version', None)
        if self.__o_class is None:
            self.__o_class = kwargs.get('__o_class', None)

    """ This method is for backward compatibility when someone
        use 'getattr(record, a_key)' """
    def __getattr__(self, item):
        """
        :param item: string
        :return: mixed
        :raise: AttributeError
        """
        try:
            return self.__o_storage[item]
        except KeyError:
            raise AttributeError( "'OrientRecord' object has no attribute "
                                  "'" + item + "'" )
pyorient/messages/base.py
class BaseMessage(object):

    def __init__(self, sock=OrientSocket):
        """
        :type sock: OrientSocket
        """
        sock.get_connection()
        self._orientSocket = sock
        self._protocol = self._orientSocket.protocol
        self._session_id = self._orientSocket.session_id

        # handles token auth
        self._auth_token = self._orientSocket.auth_token
        self._request_token = False

        self._header = []
        """:type : list of [str]"""

        self._body = []
        """:type : list of [str]"""

        self._fields_definition = []
        """:type : list of [object]"""

        self._command = chr(0)
        self._db_opened = self._orientSocket.db_opened
        self._connected = self._orientSocket.connected

        self._node_list = []
        """:type : list of [OrientNode]"""

        self._serializer = None

        self._output_buffer = b''
        self._input_buffer = b''

        # callback function for async queries
        self._callback = None

        # callback for push received from the server
        self._push_callback = None

        self._need_token = True

        global in_transaction
        in_transaction = False

    def get_serializer(self):
        """
        Lazy return of the serialization, we retrive the type from the :class: `OrientSocket <pyorient.orient.OrientSocket>` object
        :return: an Instance of the serializer suitable for decoding or encoding
        """
        if self._orientSocket.serialization_type==OrientSerialization.Binary:
            return OrientSerialization.get_impl(self._orientSocket.serialization_type,
                                                self._orientSocket._props)
        else:
            return OrientSerialization.get_impl(self._orientSocket.serialization_type)

    def get_orient_socket_instance(self):
        return self._orientSocket

    def is_connected(self):
        return self._connected is True

    def database_opened(self):
        return self._db_opened

    def get_cluster_map(self):
        """:type : list of [OrientNode]"""
        return self._node_list


    def set_session_token( self, token='' ):
        """
        :param token: Set the request to True to use the token authentication
        :type token: bool|string
        :return: self
        """
        if token != '' and token is not None:
            if type(token) is bool:
                self._request_token = token
            elif type(token) is str or type(token) is bytes:
                self._request_token = True
                self._auth_token = token
                self._db_opened = True
                self._connected = True
                self._update_socket_token()
        return self

    def get_session_token( self ):
        """
        Retrieve the session token to reuse after
        :return:
        """
        return self._auth_token

    def _update_socket_id(self):
        """Force update of socket id from inside the class"""
        self._orientSocket.session_id = self._session_id
        return self

    def _update_socket_token(self):
        """Force update of socket token from inside the class"""
        self._orientSocket.auth_token = self._auth_token
        return self

    def _reset_fields_definition(self):
        self._fields_definition = []

    def prepare(self, *args):

        # session_id
        self._fields_definition.insert( 1, ( FIELD_INT, self._session_id ) )


        """
        #  Token authentication handling
        #  we must recognize ConnectMessage and DbOpenMessage messages
        """
        if self._need_token and self._request_token is True:
            self._fields_definition.insert(
                2, ( FIELD_STRING, self._auth_token )
            )

        self._output_buffer = b''.join(
            self._encode_field( x ) for x in self._fields_definition
        )
        return self

    def get_protocol(self):
        if self._protocol < 0:
            self._protocol = self._orientSocket.protocol
        return self._protocol

    def _decode_header(self):

        # read header's information
        self._header = [ self._decode_field( FIELD_BYTE ),
                         self._decode_field( FIELD_INT ) ]

        # decode message errors and raise an exception
        if self._header[0] == 1:

            # Parse the error
            exception_class = b''
            exception_message = b''

            more = self._decode_field( FIELD_BOOLEAN )

            while more:
                # read num bytes by the field definition
                exception_class += self._decode_field( FIELD_STRING )
                exception_message += self._decode_field( FIELD_STRING )
                more = self._decode_field( FIELD_BOOLEAN )

                if self.get_protocol() > 18:  # > 18 1.6-snapshot
                    # read serialized version of exception thrown on server side
                    # useful only for java clients
                    serialized_exception = self._decode_field( FIELD_STRING )
                    # trash
                    del serialized_exception

            raise PyOrientCommandException(
                exception_class.decode( 'utf8' ),
                [ exception_message.decode( 'utf8' ) ]
            )

        elif self._header[0] == 3:
            # Push notification, Node cluster changed
            # TODO: UNTESTED CODE!!!
            # FIELD_BYTE (OChannelBinaryProtocol.PUSH_DATA);  # WRITE 3
            # FIELD_INT (Integer.MIN_VALUE);  # SESSION ID = 2^-31
            # 80: \x50 Request Push 1 byte: Push command id
            push_command_id = self._decode_field(FIELD_BYTE)
            push_message = self._decode_field( FIELD_STRING )
            _, payload = self.get_serializer().decode(push_message)
            if self._push_callback:
                self._push_callback(push_command_id, payload)

            end_flag = self._decode_field( FIELD_BYTE )

            # this flag can be set more than once
            while end_flag == 3:
                self._decode_field( FIELD_INT )  # FAKE SESSION ID = 2^-31
                op_code = self._decode_field( FIELD_BYTE )  # 80: 0x50 Request Push

                # REQUEST_PUSH_RECORD	        79
                # REQUEST_PUSH_DISTRIB_CONFIG	80
                # REQUEST_PUSH_LIVE_QUERY	    81
                if op_code == 80:
                    # for node in
                    payload = self.get_serializer().decode(
                        self._decode_field( FIELD_STRING )
                    )  # JSON WITH THE NEW CLUSTER CFG

                    # reset the nodelist
                    self._node_list = []
                    for node in payload['members']:
                        self._node_list.append( OrientNode( node ) )

                end_flag = self._decode_field( FIELD_BYTE )

            # Try to set the new session id???
            self._header[1] = self._decode_field( FIELD_INT )  # REAL SESSION ID
            pass

        from .connection import ConnectMessage
        from .database import DbOpenMessage
        """
        #  Token authentication handling
        #  we must recognize ConnectMessage and DbOpenMessage messages
            TODO: change this check avoiding cross import,
            importing a subclass in a super class is bad
        """
        if not isinstance(self, (ConnectMessage, DbOpenMessage)) \
                and self._request_token is True:
            token_refresh = self._decode_field(FIELD_STRING)
            if token_refresh != b'':
                self._auth_token = token_refresh
                self._update_socket_token()

    def _decode_body(self):
        # read body
        for field in self._fields_definition:
            self._body.append( self._decode_field( field ) )

        # clear field stack
        self._reset_fields_definition()
        return self

    def _decode_all(self):
        self._decode_header()
        self._decode_body()

    def fetch_response(self, *_continue):
        """
        # Decode header and body
        # If flag continue is set( Header already read ) read only body
        :param _continue:
        :return:
        """
        if len(_continue) is not 0:
            self._body = []
            self._decode_body()
            self.dump_streams()
        # already fetched, get last results as cache info
        elif len(self._body) is 0:
            self._decode_all()
            self.dump_streams()
        return self._body

    def dump_streams(self):
        if is_debug_active():
            if len( self._output_buffer ):
                print("\nRequest :")
                hexdump( self._output_buffer )
                # print(repr(self._output_buffer))
            if len( self._input_buffer ):
                print("\nResponse:")
                hexdump( self._input_buffer )
                # print(repr(self._input_buffer))

    def _append(self, field):
        """
        @:rtype self: BaseMessage
        @type field: object
        """
        self._fields_definition.append( field )
        return self

    def __str__(self):

        return "\n_output_buffer: \n" + hexdump( self._output_buffer, 'return' ) \
               + "\n\n_input_buffer: \n" + hexdump( self._input_buffer, 'return' )

    def send(self):
        if self._orientSocket.in_transaction is False:
            self._orientSocket.write( self._output_buffer )
            self._reset_fields_definition()
        if is_debug_active():
            self.dump_streams()
            # reset output buffer
            self._output_buffer = b""

        return self

    def close(self):
        self._orientSocket.close()

    @staticmethod
    def _encode_field(field):

        # tuple with type
        t, v = field
        _content = None

        if t['type'] == INT:
            _content = struct.pack("!i", v)
        elif t['type'] == SHORT:
            _content = struct.pack("!h", v)
        elif t['type'] == LONG:
            _content = struct.pack("!q", v)
        elif t['type'] == BOOLEAN:
            if sys.version_info[0] < 3:
                _content = chr(1) if v else chr(0)
            else:
                _content = bytes([1]) if v else bytes([0])
        elif t['type'] == BYTE:
            if sys.version_info[0] < 3:
                _content = v
            else:
                _content = bytes([ord(v)])
        elif t['type'] == BYTES:
            _content = struct.pack("!i", len(v)) + v
        elif t['type'] == STRING:
            if sys.version_info[0] >= 3:
                if isinstance(v, str):
                    v = v.encode('utf-8')
            else:
                if isinstance(v, unicode):
                    v = v.encode('utf-8')
            _content = struct.pack("!i", len(v)) + v
        elif t['type'] == STRINGS:
            _content = b''
            for s in v:
                if sys.version_info[0] >= 3:
                    if isinstance(s, str):
                        s = s.encode('utf-8')
                else:
                    if isinstance(s, unicode):
                        s = s.encode('utf-8')
                _content += struct.pack("!i", len(s)) + s

        return _content

    def _decode_field(self, _type):
        _value = b""
        # read buffer length and decode value by field definition
        if _type['bytes'] is not None:
            _value = self._orientSocket.read( _type['bytes'] )
        # if it is a string decode first 4 Bytes as INT
        # and try to read the buffer
        if _type['type'] == STRING or _type['type'] == BYTES:

            _len = struct.unpack('!i', _value)[0]
            if _len == -1 or _len == 0:
                _decoded_string = b''
            else:
                _decoded_string = self._orientSocket.read( _len )

            self._input_buffer += _value
            self._input_buffer += _decoded_string

            return _decoded_string

        elif _type['type'] == RECORD:

            # record_type
            record_type = self._decode_field( _type['struct'][0] )

            rid = "#" + str( self._decode_field( _type['struct'][1] ) )
            rid += ":" + str( self._decode_field( _type['struct'][2] ) )
            
            version = self._decode_field( _type['struct'][3] )
            content = self._decode_field( _type['struct'][4] )
            return {'rid': rid, 'record_type': record_type,
                    'content': content, 'version': version}

        elif _type['type'] == LINK:

            rid = "#" + str( self._decode_field( _type['struct'][0] ) )
            rid += ":" + str( self._decode_field( _type['struct'][1] ) )
            return rid

        else:
            self._input_buffer += _value

            if _type['type'] == BOOLEAN:
                return ord(_value) == 1
            elif _type['type'] == BYTE:
                return ord(_value)
            elif _type['type'] == CHAR:
                return _value
            elif _type['type'] == SHORT:
                return struct.unpack('!h', _value)[0]
            elif _type['type'] == INT:
                return struct.unpack('!i', _value)[0]
            elif _type['type'] == LONG:
                return struct.unpack('!q', _value)[0]

    def _read_async_records(self):
        """
        # async-result-type byte as trailing byte of a record can be:
        # 0: no records remain to be fetched
        # 1: a record is returned as a result set
        # 2: a record is returned as pre-fetched to be loaded in client's
        #       cache only. It's not part of the result set but the client
        #       knows that it's available for later access
        """
        _status = self._decode_field( FIELD_BYTE )  # status

        while _status != 0:

            try:

                # if a callback for the cache is not set, raise exception
                if not hasattr(self._callback, '__call__'):
                    raise AttributeError()

                _record = self._read_record()

                if _status == 1:  # async record type
                    # async_records.append( _record )  # save in async
                    self._callback( _record )  # save in async
                elif _status == 2:  # cache
                    # cached_records.append( _record )  # save in cache
                    self._callback( _record )  # save in cache

            except AttributeError:
                # AttributeError: 'RecordLoadMessage' object has
                # no attribute '_command_type'
                raise PyOrientBadMethodCallException(
                    str(self._callback) + " is not a callable function", [])
            finally:
                # read new status and flush the debug buffer
                _status = self._decode_field( FIELD_BYTE )  # status

    def _read_record(self):
        """
        # The format depends if a RID is passed or an entire
            record with its content.

        # In case of null record then -2 as short is passed.

        # In case of RID -3 is passes as short and then the RID:
            (-3:short)(cluster-id:short)(cluster-position:long).

        # In case of record:
            (0:short)(record-type:byte)(cluster-id:short)
            (cluster-position:long)(record-version:int)(record-content:bytes)

        :raise: PyOrientNullRecordException
        :return: OrientRecordLink,OrientRecord
        """
        marker = self._decode_field( FIELD_SHORT )  # marker

        if marker is -2:
            raise PyOrientNullRecordException('NULL Record', [])
        elif marker is -3:
            res = OrientRecordLink( self._decode_field( FIELD_TYPE_LINK ) )
        else:
            # read record
            __res = self._decode_field( FIELD_RECORD )
            
            if self._orientSocket.serialization_type==OrientSerialization.Binary:
                class_name, data = self.get_serializer().decode(__res['content'])
            else:
                # bug in orientdb csv serialization in snapshot 2.0
                class_name, data = self.get_serializer().decode(__res['content'].rstrip())


            res = OrientRecord(
                dict(
                    __o_storage=data,
                    __o_class=class_name,
                    __version=__res['version'],
                    __rid=__res['rid']
                )
            )

        self.dump_streams()  # debug log
        self._output_buffer = b''
        self._input_buffer = b''

        return res
pyorient/constants.py
FIELD_LONG = {"type": LONG, "bytes": 8, "struct": None}
pyorient/constants.py
DB_DROP_OP                 = chr(7)
pyorient/constants.py
DB_TYPES            = (
    DB_TYPE_DOCUMENT,
    DB_TYPE_GRAPH,
)
pyorient/exceptions.py
class PyOrientBadMethodCallException(PyOrientException):
    pass
pyorient/constants.py
FIELD_STRINGS = {"type": STRINGS, "bytes": 4, "struct": None}
pyorient/constants.py
FIELD_BYTE = {"type": BYTE, "bytes": 1, "struct": None}
pyorient/otypes.py
class OrientCluster(object):
    def __init__(self, name, cluster_id, cluster_type=None, segment=None):
        """
        Information regarding a Cluster on the Orient Server
        :param name: str name of the cluster
        :param id: int id of the cluster
        :param type: cluster type (only for version <24 of the protocol)
        :param segment: cluster segment (only for version <24 of the protocol)
        """
        #: str name of the cluster
        self.name = name
        #: int idof the cluster
        self.id = cluster_id
        self.type = cluster_type
        self.segment = segment

    def __str__(self):
        return "%s: %d" % (self.name, self.id)

    def __eq__(self, other):
        return self.name == other.name and self.id == other.id

    def __ne__(self, other):
        return self.name != other.name or self.id != other.id
pyorient/constants.py
DB_LIST_OP                 = chr(74)
pyorient/constants.py
NAME = "OrientDB Python binary client (pyorient)"
pyorient/serializations.py
class OrientSerialization(object):
    """
    Enum representing the available serialization
    """
    #: CSV the default serialization
    CSV = "ORecordDocument2csv"

    #: Now unimplemented
    Binary = "ORecordSerializerBinary"

    @classmethod
    def get_impl(cls, impl, props=None):
        impl_map = {
            cls.CSV: OrientSerializationCSV,
            cls.Binary: OrientSerializationBinary,
        }
        implementation = impl_map.get(impl, False)
        if not implementation:
            raise PyOrientBadMethodCallException(
                impl + ' is not an available serialization type', []
            )
        if impl == cls.Binary:
            if not binary_support:
                raise Exception( "To support Binary Serialization, pyorient_native must be installed" )
            return implementation(props)
        else:
            return implementation()
pyorient/constants.py
STORAGE_TYPES       = (
    STORAGE_TYPE_LOCAL,
    STORAGE_TYPE_PLOCAL,
    STORAGE_TYPE_MEMORY,
)
pyorient/constants.py
DB_OPEN_OP                 = chr(3)


Question: from pyorient.exceptions import PyOrientBadMethodCallException
from .base import BaseMessage
from ..constants import DB_OPEN_OP, DB_TYPE_DOCUMENT, DB_COUNT_RECORDS_OP, FIELD_BYTE, FIELD_INT, \
    FIELD_SHORT, FIELD_STRING, FIELD_STRINGS, FIELD_BYTES, FIELD_BOOLEAN, NAME, SUPPORTED_PROTOCOL, \
    VERSION, DB_TYPES, DB_CLOSE_OP, DB_EXIST_OP, STORAGE_TYPE_PLOCAL, \
    STORAGE_TYPE_LOCAL, DB_CREATE_OP, \
    DB_DROP_OP, DB_RELOAD_OP, DB_SIZE_OP, DB_LIST_OP, STORAGE_TYPES, FIELD_LONG
from ..utils import need_connected, need_db_opened
from ..otypes import OrientRecord, OrientCluster, OrientVersion, OrientNode
from ..serializations import OrientSerialization

        return info, clusters, self._node_list
        # self._cluster_map = self._orientSocket.cluster_map = \
        #     Information([clusters, response, self._orientSocket])

        # return self._cluster_map

    def set_db_name(self, db_name):
        self._db_name = db_name
        return self

    def set_db_type(self, db_type):
        if db_type in DB_TYPES:
            # user choice storage if present
            self._db_type = db_type
        else:
            raise PyOrientBadMethodCallException(
                db_type + ' is not a valid database type', []
            )
        return self

    def set_client_id(self, _cid):
        self._client_id = _cid
        return self

    def set_user(self, _user):
        self._user = _user
        return self

    def set_pass(self, _pass):
        self._pass = _pass
        return self


#
# DB CLOSE
#
# Closes the database and the network connection to the OrientDB Server
# instance. No return is expected. The socket is also closed.
#
# Request: empty
# Response: no response, the socket is just closed at server side
#
class DbCloseMessage(BaseMessage):
    def __init__(self, _orient_socket):
        super(DbCloseMessage, self).__init__(_orient_socket)

        # order matters
        self._append(( FIELD_BYTE, DB_CLOSE_OP ))

    @need_connected
    def prepare(self, params=None):
        return super(DbCloseMessage, self).prepare()

    def fetch_response(self):
        # set database closed
        self._orientSocket.db_opened = None
        super(DbCloseMessage, self).close()
        return 0


#
# DB EXISTS
#
# Asks if a database exists in the OrientDB Server instance. It returns true (non-zero) or false (zero).
#
# Request: (database-name:string) <-- before 1.0rc1 this was empty (server-storage-type:string - since 1.5-snapshot)
# Response: (result:byte)
#
# server-storage-type can be one of the supported types:
# plocal as a persistent database
# memory, as a volatile database
#
class DbExistsMessage(BaseMessage):
    def __init__(self, _orient_socket):
        super(DbExistsMessage, self).__init__(_orient_socket)

        self._db_name = ''
        self._storage_type = ''

        if self.get_protocol() > 16:  # 1.5-SNAPSHOT
            self._storage_type = STORAGE_TYPE_PLOCAL
        else:
            self._storage_type = STORAGE_TYPE_LOCAL

        # order matters
        self._append(( FIELD_BYTE, DB_EXIST_OP ))

    @need_connected
    def prepare(self, params=None):

        if isinstance(params, tuple) or isinstance(params, list):
            try:
                self._db_name = params[0]
                # user choice storage if present
                self.set_storage_type(params[1])

            except IndexError:
                # Use default for non existent indexes
                pass

        if self.get_protocol() >= 6:
            self._append(( FIELD_STRING, self._db_name ))  # db_name

        if self.get_protocol() >= 16:
            # > 16 1.5-snapshot
            # custom choice server_storage_type
            self._append(( FIELD_STRING, self._storage_type ))

        return super(DbExistsMessage, self).prepare()

    def fetch_response(self):
        self._append(FIELD_BOOLEAN)
        return super(DbExistsMessage, self).fetch_response()[0]

    def set_db_name(self, db_name):
        self._db_name = db_name
        return self

    def set_storage_type(self, storage_type):

Answer:         if storage_type in STORAGE_TYPES: