# Path: src/foolscap/tokens.py
# class BananaError(Exception):
#     """This exception is raised in response to a fundamental protocol
#     violation. The connection should be dropped immediately.
# 
#     .where is an optional string that describes the node of the object graph
#     where the failure was noticed.
#     """
#     where = None
# 
#     def __str__(self):
#         if self.where:
#             return "BananaError(in %s): %s" % (self.where, self.args)
#         else:
#             return "BananaError: %s" % (self.args,)
# 
# class Violation(Exception):
#     """This exception is raised in response to a schema violation. It
#     indicates that the incoming token stream has violated a constraint
#     imposed by the recipient. The current Unslicer is abandoned and the
#     error is propagated upwards to the enclosing Unslicer parent by
#     providing an BananaFailure object to the parent's .receiveChild method.
#     All remaining tokens for the current Unslicer are to be dropped.
#     """
# 
#     """.where: this string describes which node of the object graph was
#     being handled when the exception took place."""
#     where = ""
# 
#     def setLocation(self, where):
#         self.where = where
#     def getLocation(self):
#         return self.where
#     def prependLocation(self, prefix):
#         if self.where:
#             self.where = prefix + " " + self.where
#         else:
#             self.where = prefix
#     def appendLocation(self, suffix):
#         if self.where:
#             self.where = self.where + " " + suffix
#         else:
#             self.where = suffix
# 
#     def __str__(self):
#         if self.where:
#             return "Violation (%s): %s" % (self.where, self.args)
#         else:
#             return "Violation: %s" % (self.args,)


import six
from twisted.python import failure, reflect, log as twlog
from twisted.internet import defer
from foolscap import copyable, slicer, tokens
from foolscap.copyable import AttributeDictConstraint
from foolscap.constraint import ByteStringConstraint
from foolscap.slicers.list import ListConstraint
from .tokens import BananaError, Violation
from foolscap.util import AsyncAND
from foolscap.logging import log

            # TODO: make this faster. A likely optimization is to take a
            # tuple of components.getInterfaces(obj) and use it as a cache
            # key. It would be even faster to use obj.__class__, but that
            # would probably violate the expectation that instances can
            # define their own __implements__ (independently from their
            # class). If this expectation were to go away, a quick
            # obj.__class__ -> RemoteReferenceSchema cache could be built.

            assert ready_deferred is None
            self.stage = 3

            if self.objID < 0:
                # the target is a bound method, ignore the methodname
                self.methodSchema = getattr(self.obj, "methodSchema", None)
                self.methodname = None # TODO: give it something useful
                if self.broker.requireSchema and not self.methodSchema:
                    why = "This broker does not accept unconstrained " + \
                          "method calls"
                    raise Violation(why)
                return

            self.methodname = six.ensure_str(token)

            if self.interface:
                # they are calling an interface+method pair
                ms = self.interface.get(self.methodname)
                if not ms:
                    why = "method '%s' not defined in %s" % \
                          (self.methodname, self.interface.__remote_name__)

# Path: src/foolscap/tokens.py
# class BananaError(Exception):
#     """This exception is raised in response to a fundamental protocol
#     violation. The connection should be dropped immediately.
# 
#     .where is an optional string that describes the node of the object graph
#     where the failure was noticed.
#     """
#     where = None
# 
#     def __str__(self):
#         if self.where:
#             return "BananaError(in %s): %s" % (self.where, self.args)
#         else:
#             return "BananaError: %s" % (self.args,)
# 
# class Violation(Exception):
#     """This exception is raised in response to a schema violation. It
#     indicates that the incoming token stream has violated a constraint
#     imposed by the recipient. The current Unslicer is abandoned and the
#     error is propagated upwards to the enclosing Unslicer parent by
#     providing an BananaFailure object to the parent's .receiveChild method.
#     All remaining tokens for the current Unslicer are to be dropped.
#     """
# 
#     """.where: this string describes which node of the object graph was
#     being handled when the exception took place."""
#     where = ""
# 
#     def setLocation(self, where):
#         self.where = where
#     def getLocation(self):
#         return self.where
#     def prependLocation(self, prefix):
#         if self.where:
#             self.where = prefix + " " + self.where
#         else:
#             self.where = prefix
#     def appendLocation(self, suffix):
#         if self.where:
#             self.where = self.where + " " + suffix
#         else:
#             self.where = suffix
# 
#     def __str__(self):
#         if self.where:
#             return "Violation (%s): %s" % (self.where, self.args)
#         else:
#             return "Violation: %s" % (self.args,)


# Path: src/foolscap/call.py
import six
from twisted.python import failure, reflect, log as twlog
from twisted.internet import defer
from foolscap import copyable, slicer, tokens
from foolscap.copyable import AttributeDictConstraint
from foolscap.constraint import ByteStringConstraint
from foolscap.slicers.list import ListConstraint
from .tokens import BananaError, Violation
from foolscap.util import AsyncAND
from foolscap.logging import log


            # TODO: make this faster. A likely optimization is to take a
            # tuple of components.getInterfaces(obj) and use it as a cache
            # key. It would be even faster to use obj.__class__, but that
            # would probably violate the expectation that instances can
            # define their own __implements__ (independently from their
            # class). If this expectation were to go away, a quick
            # obj.__class__ -> RemoteReferenceSchema cache could be built.

            assert ready_deferred is None
            self.stage = 3

            if self.objID < 0:
                # the target is a bound method, ignore the methodname
                self.methodSchema = getattr(self.obj, "methodSchema", None)
                self.methodname = None # TODO: give it something useful
                if self.broker.requireSchema and not self.methodSchema:
                    why = "This broker does not accept unconstrained " + \
                          "method calls"
                    raise Violation(why)
                return

            self.methodname = six.ensure_str(token)

            if self.interface:
                # they are calling an interface+method pair
                ms = self.interface.get(self.methodname)
                if not ms:
                    why = "method '%s' not defined in %s" % \
                          (self.methodname, self.interface.__remote_name__)

                    raise Violation(why)