This file is indexed.

/usr/lib/python2.7/dist-packages/foolscap/remoteinterface.py is in python-foolscap 0.6.4-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
import types
import inspect
from zope.interface import interface, providedBy, implements
from foolscap.constraint import Constraint, OpenerConstraint, nothingTaster, \
     IConstraint, IRemoteMethodConstraint, Optional, Any
from foolscap.tokens import Violation, InvalidRemoteInterface
from foolscap.schema import addToConstraintTypeMap
from foolscap import ipb

class RemoteInterfaceClass(interface.InterfaceClass):
    """This metaclass lets RemoteInterfaces be a lot like Interfaces. The
    methods are parsed differently (PB needs more information from them than
    z.i extracts, and the methods can be specified with a RemoteMethodSchema
    directly).

    RemoteInterfaces can accept the following additional attribute::

     __remote_name__: can be set to a string to specify the globally-unique
                      name for this interface. This should be a URL in a
                      namespace you administer. If not set, defaults to the
                      short classname.

    RIFoo.names() returns the list of remote method names.

    RIFoo['bar'] is still used to get information about method 'bar', however
    it returns a RemoteMethodSchema instead of a z.i Method instance.

    """

    def __init__(self, iname, bases=(), attrs=None, __module__=None):
        if attrs is None:
            interface.InterfaceClass.__init__(self, iname, bases, attrs,
                                              __module__)
            return

        # parse (and remove) the attributes that make this a RemoteInterface
        try:
            rname, remote_attrs = self._parseRemoteInterface(iname, attrs)
        except:
            raise

        # now let the normal InterfaceClass do its thing
        interface.InterfaceClass.__init__(self, iname, bases, attrs,
                                          __module__)

        # now add all the remote methods that InterfaceClass would have
        # complained about. This is really gross, and it really makes me
        # question why we're bothing to inherit from z.i.Interface at all. I
        # will probably stop doing that soon, and just have our own
        # meta-class, but I want to make sure you can still do
        # 'implements(RIFoo)' from within a class definition.

        a = getattr(self, "_InterfaceClass__attrs") # the ickiest part
        a.update(remote_attrs)
        self.__remote_name__ = rname

        # finally, auto-register the interface
        try:
            registerRemoteInterface(self, rname)
        except:
            raise

    def _parseRemoteInterface(self, iname, attrs):
        remote_attrs = {}

        remote_name = attrs.get("__remote_name__", iname)

        # and see if there is a __remote_name__ . We delete it because
        # InterfaceClass doesn't like arbitrary attributes
        if attrs.has_key("__remote_name__"):
            del attrs["__remote_name__"]

        # determine all remotely-callable methods
        names = [name for name in attrs.keys()
                 if ((type(attrs[name]) == types.FunctionType and
                      not name.startswith("_")) or
                     IConstraint.providedBy(attrs[name]))]

        # turn them into constraints. Tag each of them with their name and
        # the RemoteInterface they came from.
        for name in names:
            m = attrs[name]
            if not IConstraint.providedBy(m):
                m = RemoteMethodSchema(method=m)
            m.name = name
            m.interface = self
            remote_attrs[name] = m
            # delete the methods, so zope's InterfaceClass doesn't see them.
            # Particularly necessary for things defined with IConstraints.
            del attrs[name]

        return remote_name, remote_attrs

RemoteInterface = RemoteInterfaceClass("RemoteInterface",
                                       __module__="pb.flavors")



def getRemoteInterface(obj):
    """Get the (one) RemoteInterface supported by the object, or None."""
    interfaces = list(providedBy(obj))
    # TODO: versioned Interfaces!
    ilist = []
    for i in interfaces:
        if isinstance(i, RemoteInterfaceClass):
            if i not in ilist:
                ilist.append(i)
    assert len(ilist) <= 1, ("don't use multiple RemoteInterfaces! %s uses %s"
                             % (obj, ilist))
    if ilist:
        return ilist[0]
    return None

class DuplicateRemoteInterfaceError(Exception):
    pass

RemoteInterfaceRegistry = {}
def registerRemoteInterface(iface, name=None):
    if not name:
        name = iface.__remote_name__
    assert isinstance(iface, RemoteInterfaceClass)
    if RemoteInterfaceRegistry.has_key(name):
        old = RemoteInterfaceRegistry[name]
        msg = "remote interface %s was registered with the same name (%s) as %s, please use __remote_name__ to provide a unique name" % (old, name, iface)
        raise DuplicateRemoteInterfaceError(msg)
    RemoteInterfaceRegistry[name] = iface

def getRemoteInterfaceByName(iname):
    return RemoteInterfaceRegistry.get(iname)



class RemoteMethodSchema(object):
    """
    This is a constraint for a single remotely-invokable method. It gets to
    require, deny, or impose further constraints upon a set of named
    arguments.

    This constraint is created by using keyword arguments with the same
    names as the target method's arguments. Two special names are used:

    __ignoreUnknown__: if True, unexpected argument names are silently
    dropped. (note that this makes the schema unbounded)

    __acceptUnknown__: if True, unexpected argument names are always
    accepted without a constraint (which also makes this schema unbounded)

    The remotely-accesible object's .getMethodSchema() method may return one
    of these objects.
    """

    implements(IRemoteMethodConstraint)

    taster = {} # this should not be used as a top-level constraint
    opentypes = [] # overkill
    ignoreUnknown = False
    acceptUnknown = False

    name = None # method name, set when the RemoteInterface is parsed
    interface = None # points to the RemoteInterface which defines the method

    # under development
    def __init__(self, method=None, _response=None, __options=[], **kwargs):
        if method:
            self.initFromMethod(method)
            return
        self.argumentNames = []
        self.argConstraints = {}
        self.required = []
        self.responseConstraint = None
        # __response in the argslist gets treated specially, I think it is
        # mangled into _RemoteMethodSchema__response or something. When I
        # change it to use _response instead, it works.
        if _response:
            self.responseConstraint = IConstraint(_response)
        self.options = {} # return, wait, reliable, etc

        if kwargs.has_key("__ignoreUnknown__"):
            self.ignoreUnknown = kwargs["__ignoreUnknown__"]
            del kwargs["__ignoreUnknown__"]
        if kwargs.has_key("__acceptUnknown__"):
            self.acceptUnknown = kwargs["__acceptUnknown__"]
            del kwargs["__acceptUnknown__"]

        for argname, constraint in kwargs.items():
            self.argumentNames.append(argname)
            constraint = IConstraint(constraint)
            self.argConstraints[argname] = constraint
            if not isinstance(constraint, Optional):
                self.required.append(argname)

    def initFromMethod(self, method):
        # call this with the Interface's prototype method: the one that has
        # argument constraints expressed as default arguments, and which
        # does nothing but returns the appropriate return type

        names, _, _, typeList = inspect.getargspec(method)
        if names and names[0] == 'self':
            why = "RemoteInterface methods should not have 'self' in their argument list"
            raise InvalidRemoteInterface(why)
        if not names:
            typeList = []
        # 'def foo(oops)' results in typeList==None
        if typeList is None or len(names) != len(typeList):
            # TODO: relax this, use schema=Any for the args that don't have
            # default values. This would make:
            #  def foo(a, b=int): return None
            # equivalent to:
            #  def foo(a=Any, b=int): return None
            why = "RemoteInterface methods must have default values for all their arguments"
            raise InvalidRemoteInterface(why)
        self.argumentNames = names
        self.argConstraints = {}
        self.required = []
        for i in range(len(names)):
            argname = names[i]
            constraint = typeList[i]
            if not isinstance(constraint, Optional):
                self.required.append(argname)
            self.argConstraints[argname] = IConstraint(constraint)

        # call the method, its 'return' value is the return constraint
        self.responseConstraint = IConstraint(method())
        self.options = {} # return, wait, reliable, etc


    def getPositionalArgConstraint(self, argnum):
        if argnum >= len(self.argumentNames):
            raise Violation("too many positional arguments: %d >= %d" %
                            (argnum, len(self.argumentNames)))
        argname = self.argumentNames[argnum]
        c = self.argConstraints.get(argname)
        assert c
        if isinstance(c, Optional):
            c = c.constraint
        return (True, c)

    def getKeywordArgConstraint(self, argname,
                                num_posargs=0, previous_kwargs=[]):
        previous_args = self.argumentNames[:num_posargs]
        for pkw in previous_kwargs:
            assert pkw not in previous_args
            previous_args.append(pkw)
        if argname in previous_args:
            raise Violation("got multiple values for keyword argument '%s'"
                            % (argname,))
        c = self.argConstraints.get(argname)
        if c:
            if isinstance(c, Optional):
                c = c.constraint
            return (True, c)
        # what do we do with unknown arguments?
        if self.ignoreUnknown:
            return (False, None)
        if self.acceptUnknown:
            return (True, None)
        raise Violation("unknown argument '%s'" % argname)

    def getResponseConstraint(self):
        return self.responseConstraint

    def checkAllArgs(self, args, kwargs, inbound):
        # first we map the positional arguments
        allargs = {}
        if len(args) > len(self.argumentNames):
            raise Violation("method takes %d positional arguments (%d given)"
                            % (len(self.argumentNames), len(args)))
        for i,argvalue in enumerate(args):
            allargs[self.argumentNames[i]] = argvalue
        for argname,argvalue in kwargs.items():
            if argname in allargs:
                raise Violation("got multiple values for keyword argument '%s'"
                                % (argname,))
            allargs[argname] = argvalue

        for argname, argvalue in allargs.items():
            accept, constraint = self.getKeywordArgConstraint(argname)
            if not accept:
                # this argument will be ignored by the far end. TODO: emit a
                # warning
                pass
            try:
                constraint.checkObject(argvalue, inbound)
            except Violation, v:
                v.setLocation("%s=" % argname)
                raise

        for argname in self.required:
            if argname not in allargs:
                raise Violation("missing required argument '%s'" % argname)

    def checkResults(self, results, inbound):
        if self.responseConstraint:
            # this might raise a Violation. The caller will annotate its
            # location appropriately: they have more information than we do.
            self.responseConstraint.checkObject(results, inbound)

class UnconstrainedMethod(object):
    """I am a method constraint that accepts any arguments and any return
    value.

    To use this, assign it to a method name in a RemoteInterface::

     class RIFoo(RemoteInterface):
         def constrained_method(foo=int, bar=str): # this one is constrained
             return str
         not_method = UnconstrainedMethod()  # this one is not
    """
    implements(IRemoteMethodConstraint)

    def getPositionalArgConstraint(self, argnum):
        return (True, Any())
    def getKeywordArgConstraint(self, argname, num_posargs=0,
                                previous_kwargs=[]):
        return (True, Any())
    def checkAllArgs(self, args, kwargs, inbound):
        pass # accept everything
    def getResponseConstraint(self):
        return Any()
    def checkResults(self, results, inbound):
        pass # accept everything


class LocalInterfaceConstraint(Constraint):
    """This constraint accepts any (local) instance which implements the
    given local Interface.
    """

    # TODO: maybe accept RemoteCopy instances
    # TODO: accept inbound your-references, if the local object they map to
    #       implements the interface

    # TODO: do we need an string-to-Interface map just like we have a
    # classname-to-class/factory map?
    taster = nothingTaster
    opentypes = []
    name = "LocalInterfaceConstraint"

    def __init__(self, interface):
        self.interface = interface
    def checkObject(self, obj, inbound):
        # TODO: maybe try to get an adapter instead?
        if not self.interface.providedBy(obj):
            raise Violation("'%s' does not provide interface %s"
                            % (obj, self.interface))

class RemoteInterfaceConstraint(OpenerConstraint):
    """This constraint accepts any RemoteReference that claims to be
    associated with a remote Referenceable that implements the given
    RemoteInterface. If 'interface' is None, just assert that it is a
    RemoteReference at all.

    On the inbound side, this will only accept a suitably-implementing
    RemoteReference, or a gift that resolves to such a RemoteReference. On
    the outbound side, this will accept either a Referenceable or a
    RemoteReference (which might be a your-reference or a their-reference).

    Sending your-references will result in the recipient getting a local
    Referenceable, which will not pass the constraint. TODO: think about if
    we want this behavior or not.
    """

    opentypes = [("my-reference",), ("their-reference",)]
    name = "RemoteInterfaceConstraint"

    def __init__(self, interface):
        self.interface = interface
    def checkObject(self, obj, inbound):
        if inbound:
            # this ought to be a RemoteReference that claims to be associated
            # with a remote Referenceable that implements the desired
            # interface.
            if not ipb.IRemoteReference.providedBy(obj):
                raise Violation("'%s' does not provide RemoteInterface %s, "
                                "and doesn't even look like a RemoteReference"
                                % (obj, self.interface))
            if not self.interface:
                return
            iface = obj.tracker.interface
            # TODO: this test probably doesn't handle subclasses of
            # RemoteInterface, which might be useful (if it even works)
            if not iface or iface != self.interface:
                raise Violation("'%s' does not provide RemoteInterface %s"
                                % (obj, self.interface))
        else:
            # this ought to be a Referenceable which implements the desired
            # interface. Or, it might be a RemoteReference which points to
            # one.
            if ipb.IRemoteReference.providedBy(obj):
                # it's a RemoteReference
                if not self.interface:
                    return
                iface = obj.tracker.interface
                if not iface or iface != self.interface:
                    raise Violation("'%s' does not provide RemoteInterface %s"
                                    % (obj, self.interface))
                return
            if not ipb.IReferenceable.providedBy(obj):
                # TODO: maybe distinguish between OnlyReferenceable and
                # Referenceable? which is more useful here?
                raise Violation("'%s' is not a Referenceable" % (obj,))
            if self.interface and not self.interface.providedBy(obj):
                raise Violation("'%s' does not provide RemoteInterface %s"
                                % (obj, self.interface))

def _makeConstraint(t):
    # This will be called for both local interfaces (IFoo) and remote
    # interfaces (RIFoo), so we have to distinguish between them. The late
    # import is to deal with a circular reference between this module and
    # remoteinterface.py
    if isinstance(t, RemoteInterfaceClass):
        return RemoteInterfaceConstraint(t)
    return LocalInterfaceConstraint(t)

addToConstraintTypeMap(interface.InterfaceClass, _makeConstraint)