1

I'm probably missing something obvious, but I've been trying to solve this problem for about an hour, without any success. Probably going to feel really stupid when the solution is found. Here's the error I'm getting:

  File "xpc_connection.py", line 77
    def remoteObjectProxy():
    ^
IndentationError: unexpected indent

If I delete that portion of code, I get an indent error for the next line. There are some super strange problems going on with my indenting ...

Here's my code (yes, I know it's rather incomplete, and may have a few issues):

from collections import namedtuple;
import socket;
import sys;
from recvTimeout import recv_timeout
from recvTimeout import recv_end
from recvTimeout import sendAllWithEnd


# Named tuple that defines struct-like structure.
# field1 - body length, field2 - headerChecksum, field3 - checksum
XPCMessageHeader = namedtuple("XPCMessageHeader", "field1 field2 field3");


class XPCConnection(object):
    """An class that represents a connection made between processes using XPC.

    Attributes:

    """

    def __init__(self, serviceName):
        self._serviceName = serviceName;
        self._exportedObject = None;            # This process's "representation" of itself.
        self._remoteObjectProxy = None;         # This process's "representation" of the remote process.
        self._exportedObjectInterface = None;   # Methods allowed to be received by exported object on this connection.
        self._remoteObjectInterface = None;     # Methods allowed to be received by object that has been "imported"
                                                # to this connection.
        self._connectionSocket = None           # Domain socket that is endpoint of connection between processes. 


    def connect():
        # Create a UDS socket
        _connectionSocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

        # Change this to port where remote process is listening.

        print >>sys.stderr, 'connecting to %s' % _serviceName

        try:
            _connectionSocket.connect(_serviceName)
        except socket.error, msg:
            print >>sys.stderr, msg
            sys.exit(1)

        print >>sys.stderr, 'Attempting to connect.'

        try:
            # Send data
            sendAllWithEnd(_connectionSocket,'Connected Successfully.')

            data = recv_end(_connectionSocket);

            print >>sys.stderr, 'received "%s"' % data;

        except socket.error:
            print >>sys.stderr, 'Connection Failed.';

    def disconnect():
        print >>sys.stderr, 'closing socket';
        _connectionSocket.close();

    def serviceName():
        return serviceName;

#TODO

'''
    def readMessage():


    def readMessage():


    def resume():

    def invalidate():
                        '''

    def remoteObjectProxy():
        return _remoteObjectProxy;

    @classmethod
    def setRemoteObjectProxy(cls):
        _remoteObjectProxy = CreateWithConnection(cls);     # Create a remoteObjectProxy object with connection
                                                            # field that is this connection object.

    def exportedObject():
        return exportedObject;

    def setExportedObject(exportedObject):
        _exportedObject = exportedObject;

'''
    # PRIVATE Helper Methods

    # invocation of type XPCInvocation, completionHandler of type XPCInvocationCompletionHandler
    # return type void
    def _invokeOnRemoteObject(invocation, completionHandler):


    # invocation of type XPCInvocation
    # return type XPCValue
    def _invokeOnExportedObject(invocation):


    # May be unnecessary for now.
    # fd of type int (represents a file descriptor)
    # return type bool (indicates success?)
    def _setFileDescriptor(int fd):


    # data of type DataRef
    # return type void
    def _write(data):

    # Probably not necessary
    # estimatedBytesToRead of type int
    # return type void
    def _readDataOnReadQueue(estimatedBytesToRead):

    # Likely necessary
    # bytes of type string, length of type int
    # return type void
    def _processDataOnReadQueue(bytes, length):

    # Likely unecessary
    # data of type DataRef
    # return type void
    def _writeDataOnWriteQueue(data):

    # error of type ErrorRef
    # return type void
    def _terminateWithErrorSync(error):

    # error of type Error Ref
    # return type void
    def _terminateWithErrorOnUserQueue(error):

    # return type bool. Returns true if connected, false otherwise
    def _isConnected():


    # delayInSecond of type int. Not sure if you can pass in an argument like this.
    # return type void
    def _connectWithExponentialBackoff(delayInSeconds = 0.0625):

    # return type bool. Returns true iff connected successfully
    def _attemptToConnect():



    # Likely unecessary
    # return type void
    def _flushRequestQueue():

    # closes connection
    # return type void
    def _disconnect():
                            '''



#TODO: Invocation handler equivalent.

# "This" process's representation of the other process.
class XPCRemoteObjectProxy(object):

    def __init__(self, connection):

        # Reference to the connection Remote Object is a part of. Necessary so that when
        # you invoke a method and get stuff back, reomte object proxy knows where to send stuff back to.
        self._connection = connection;

    def invoke(invocation):
        _connection.invokeOneRemoteObject(invocation);      # TODO: invokeOneRemoteObject


# Used to represent "this" process.
class XPCExportedObject(object):

    def __init__(self):
        self._invocationHandlersByMethodSignature = {}; # Invocation handlers stored in dictionary. Keyed by method signatures.

    # invocation is XPCInfocation object, returnValue XPCValue object
    def invoke(invocation, returnValue):

        try:
            # We directly modify returnValue here. Unsure if this acutally works.
            returnValue = _invocationHandlersByMethodSignature[methodSignature()];
            return True;

        except KeyError:
            return False;

    # Handler is of type XPCInvocationHandler and methodName is of type string.
    # Come back to this
    def registerInvocationHandlerForMethodSignature(handler, methodName):
        return True


# Used to call a method across an XPC connection.
class XPCInvocation(object):

    def __init__(self):
        self._methodSignature = "";     # Signature of method to be called.
        self._arguments = [];           # List of arguments for the called method. Elements are XPCValue objects.


    # TODO: This is definitely incorrect.
    # Make this a classmethod?
    def createFromSerializedRepresentation(serializedRepresentation):
        invocation = self.__class__();
        invocation.setMethodSignature(serializedRepresentation.methodsignature());

        for serializedValue in serializedRepresentation.values():
            invocation._arguments.append(FromSerializedRepresentation(serializedValue));
            # Note: FromSerializedRepresentation function defined in XPCValue class.
            # TODO: XPCValue Class

        return invocation;


    def getMethodSignature():
        return _methodSignature;

    def setMethodSignature(methodSignature):
        _methodSignature = methodSignature;

    def getArguments():
        return _arguments

    # Takes in an XPCValue as an argument.
    def appendArgument(value):
        _arguments.append(value);


    # TODO: This is definitely incorrect.
    # NOTE: XPCInvocationMessage has yet to be written. It is provided by protobuf.
    def serializedRepresentation():
        message = XPCInvocationMessage();
        message.set_methodsignature(_methodSignature);

        for value in _arguments:
            message.add_values().CopyFrom(value.serializedRepresentation());

        return message
7
  • 1
    Did you move this code between a linux and windows machine? If so you may have hidden characters. Something like notepad++ can help you see this and correct accordingly. Commented Jun 14, 2016 at 23:15
  • No, I did not. I've been typing it up in Sublime the entire time. However, what I'm doing implementing another program written in C++ in Python, and a few times I copied some C++ code over then converted it to python. Maybe I copied some hidden characters along the way ... Commented Jun 14, 2016 at 23:17
  • @PadraicCunningham I just converted all of my tabs to spaces, using a sublime feature, and according to sublime I only have spaces. Commented Jun 14, 2016 at 23:18
  • 1
    Move the first ''' in four spaces, indentation matters including strings. Commented Jun 14, 2016 at 23:19
  • I fixed it but I don't understand why this worked. What I did was I changed all of the docstrings to comments (ie, I just put a # at the beginning of every line). No idea what's going on, really. Commented Jun 14, 2016 at 23:21

1 Answer 1

5

You're using multi-line strings to substitute for multi-line comments. They are not comments, however, and when they're dedented all the way out like that, then it terminates the class scope and you can't get back into it.

Quick fix, indent the opening ''' to match the class scope.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.