pyorient/exceptions.py
class PyOrientBadMethodCallException(PyOrientException):
    pass
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/constants.py
BYTES   = 6  # Used for binary data.
pyorient/constants.py
STRINGS = 9
pyorient/constants.py
FIELD_BYTE = {"type": BYTE, "bytes": 1, "struct": None}
pyorient/orient.py
class OrientSocket(object):
    '''Class representing the binary connection to the database, it does all the low level comunication
    And holds information on server version and cluster map

    .. DANGER::
      Should not be used directly

    :param host: hostname of the server to connect
    :param port: integer port of the server

    '''
    def __init__(self, host, port, serialization_type=OrientSerialization.CSV ):

        self.connected = False
        self.host = host
        self.port = port
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.protocol = -1
        self.session_id = -1
        self.auth_token = b''
        self.db_opened = None
        self.serialization_type = serialization_type
        self.in_transaction = False
        self._props = None

    def get_connection(self):
        if not self.connected:
            self.connect()

        return self._socket

    def connect(self):
        '''Connects to the inner socket
        could raise :class:`PyOrientConnectionPoolException`
        '''
        dlog("Trying to connect...")
        try:
            self._socket.settimeout( SOCK_CONN_TIMEOUT )  # 30 secs of timeout
            self._socket.connect( (self.host, self.port) )
            _value = self._socket.recv( FIELD_SHORT['bytes'] )

            if len(_value) != 2:
                self._socket.close()

                raise PyOrientConnectionPoolException(
                    "Server sent empty string", []
                )

            self.protocol = struct.unpack('!h', _value)[0]
            if self.protocol > SUPPORTED_PROTOCOL:
                raise PyOrientWrongProtocolVersionException(
                    "Protocol version " + str(self.protocol) +
                    " is not supported yet by this client.", [])
            self.connected = True
        except socket.error as e:
            self.connected = False
            raise PyOrientConnectionException( "Socket Error: %s" % e, [] )

    def close(self):
        '''Close the inner connection
        '''
        self.host = ''
        self.port = 0
        self.protocol = -1
        self.session_id = -1
        self._socket.close()
        self.connected = False

    def write(self, buff):
        # This is a trick to detect server disconnection
        # or broken line issues because of
        """:see: https://docs.python.org/2/howto/sockets.html#when-sockets-die """

        try:
            _, ready_to_write, in_error = select.select(
                [], [self._socket], [self._socket], 1)
        except select.error as e:
            self.connected = False
            self._socket.close()
            raise e

        if not in_error and ready_to_write:
            self._socket.sendall(buff)
            return len(buff)
        else:
            self.connected = False
            self._socket.close()
            raise PyOrientConnectionException("Socket error", [])

    # The man page for recv says: The receive calls normally return
    #   any data available, up to the requested amount, rather than waiting
    #   for receipt of the full amount requested.
    #
    # If you need to read a given number of bytes, you need to call recv
    #   in a loop and concatenate the returned packets until
    #   you have read enough.
    def read(self, _len_to_read):

        while True:

            # This is a trick to detect server disconnection
            # or broken line issues because of
            """:see: https://docs.python.org/2/howto/sockets.html#when-sockets-die """
            try:
                ready_to_read, _, in_error = \
                    select.select( [self._socket, ], [], [self._socket, ], 30 )
            except select.error as e:
                self.connected = False
                self._socket.close()
                raise e

            if len(ready_to_read) > 0:

                buf = bytearray(_len_to_read)
                view = memoryview(buf)
                while _len_to_read:
                    n_bytes = self._socket.recv_into(view, _len_to_read)
                    if not n_bytes:
                        self._socket.close()
                        # TODO Implement re-connection to another listener

                        raise PyOrientConnectionException(
                            "Server seems to have went down", [])

                    view = view[n_bytes:]  # slicing views is cheap
                    _len_to_read -= n_bytes
                return bytes(buf)

            if len(in_error) > 0:
                self._socket.close()
                raise PyOrientConnectionException(
                    "Socket error", [])
pyorient/constants.py
INT     = 4
pyorient/constants.py
RECORD  = 8
pyorient/exceptions.py
class PyOrientCommandException(PyOrientException):
    pass
pyorient/constants.py
SHORT   = 3
pyorient/constants.py
BOOLEAN = 1  # Single byte: 1 = true, 0 = false
pyorient/constants.py
FIELD_STRING = {"type": STRING, "bytes": 4, "struct": None}
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
FIELD_TYPE_LINK = {"type": LINK, "bytes": None, "struct": [
    FIELD_SHORT,  # record_clusterID
    FIELD_LONG,   # record_position
]}
pyorient/constants.py
CHAR    = 10
pyorient/constants.py
FIELD_RECORD = {"type": RECORD, "bytes": None, "struct": [
    FIELD_CHAR,   # record_type
    FIELD_SHORT,  # record_clusterID
    FIELD_LONG,   # record_position
    FIELD_INT,    # record_version
    FIELD_BYTES   # record_content
]}
pyorient/constants.py
FIELD_SHORT = {"type": SHORT, "bytes": 2, "struct": None}
pyorient/otypes.py
class OrientRecordLink(object):
    def __init__(self, recordlink):
        cid, rpos = recordlink.split(":")
        self.__link = recordlink
        self.clusterID = cid
        self.recordPosition = rpos

    def __str__(self):
        return self.get_hash()

    def get(self):
        return self.__link

    def get_hash(self):
        return "#%s" % self.__link
pyorient/constants.py
STRING  = 7
pyorient/constants.py
LONG    = 5
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/hexdump.py
def hexdump(data, result='print'):
    """
    Transform binary data to the hex dump text format:

    00000000: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

      [x] data argument as a binary string
      [x] data argument as a file like object

    Returns result depending on the `result` argument:
      'print'     - prints line by line
      'return'    - returns single string
      'generator' - returns generator that produces lines
    """
    if PY3K and type(data) == str:
        raise TypeError('Abstract unicode data (expected bytes sequence)')

    gen = dumpgen(data)
    if result == 'generator':
        return gen
    elif result == 'return':
        return '\n'.join(gen)
    elif result == 'print':
        for line in gen:
            print(line)
    else:
        raise ValueError('Unknown value of `result` argument')
pyorient/constants.py
BYTE    = 2
pyorient/constants.py
FIELD_BOOLEAN = {"type": BOOLEAN, "bytes": 1, "struct": None}
pyorient/constants.py
LINK    = 11
pyorient/constants.py
FIELD_INT = {"type": INT, "bytes": 4, "struct": None}
pyorient/exceptions.py
class PyOrientNullRecordException(PyOrientException):
    pass


Question: import struct
import sys
from ..exceptions import PyOrientBadMethodCallException, \
    PyOrientCommandException, PyOrientNullRecordException
from ..otypes import OrientRecord, OrientRecordLink, OrientNode
from ..hexdump import hexdump
from ..constants import BOOLEAN, BYTE, BYTES, CHAR, FIELD_BOOLEAN, FIELD_BYTE, \
    FIELD_INT, FIELD_RECORD, FIELD_SHORT, FIELD_STRING, FIELD_TYPE_LINK, INT, \
    LINK, LONG, RECORD, SHORT, STRING, STRINGS
from ..utils import is_debug_active
from ..orient import OrientSocket
from ..serializations import OrientSerialization
        from .connection import ConnectMessage
        from .database import DbOpenMessage

        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''


Answer:             more = self._decode_field( FIELD_BOOLEAN )