~ubuntu-branches/ubuntu/precise/dbus-python/precise

« back to all changes in this revision

Viewing changes to .pc/python3-support.patch/dbus/proxies.py

  • Committer: Package Import Robot
  • Author(s): Simon McVittie
  • Date: 2012-01-24 19:07:26 UTC
  • mfrom: (2.2.2 experimental)
  • Revision ID: package-import@ubuntu.com-20120124190726-baugtt60mzf3tfpd
Tags: 1.0.0-1
* New upstream version 1.0.0
  - increase Python requirement to 2.6
  - build for Python 3 too
  - split python-dbus-dev into a separate package to be shared between
    versions
  - make python-dbus depend on python-dbus-dev for now, to preserve
    historical functionality (but packages which use it, like PyQt, should
    switch to depending on it explicitly)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2003-2007 Red Hat Inc. <http://www.redhat.com/>
2
 
# Copyright (C) 2003 David Zeuthen
3
 
# Copyright (C) 2004 Rob Taylor
4
 
# Copyright (C) 2005-2007 Collabora Ltd. <http://www.collabora.co.uk/>
5
 
#
6
 
# Permission is hereby granted, free of charge, to any person
7
 
# obtaining a copy of this software and associated documentation
8
 
# files (the "Software"), to deal in the Software without
9
 
# restriction, including without limitation the rights to use, copy,
10
 
# modify, merge, publish, distribute, sublicense, and/or sell copies
11
 
# of the Software, and to permit persons to whom the Software is
12
 
# furnished to do so, subject to the following conditions:
13
 
#
14
 
# The above copyright notice and this permission notice shall be
15
 
# included in all copies or substantial portions of the Software.
16
 
#
17
 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
 
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
 
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
 
# DEALINGS IN THE SOFTWARE.
25
 
 
26
 
import sys
27
 
import logging
28
 
 
29
 
try:
30
 
    from threading import RLock
31
 
except ImportError:
32
 
    from dummy_threading import RLock
33
 
 
34
 
import _dbus_bindings
35
 
from dbus._expat_introspect_parser import process_introspection_data
36
 
from dbus.exceptions import MissingReplyHandlerException, MissingErrorHandlerException, IntrospectionParserException, DBusException
37
 
 
38
 
__docformat__ = 'restructuredtext'
39
 
 
40
 
 
41
 
_logger = logging.getLogger('dbus.proxies')
42
 
 
43
 
from _dbus_bindings import LOCAL_PATH, \
44
 
                           BUS_DAEMON_NAME, BUS_DAEMON_PATH, BUS_DAEMON_IFACE,\
45
 
                           INTROSPECTABLE_IFACE
46
 
 
47
 
 
48
 
class _DeferredMethod:
49
 
    """A proxy method which will only get called once we have its
50
 
    introspection reply.
51
 
    """
52
 
    def __init__(self, proxy_method, append, block):
53
 
        self._proxy_method = proxy_method
54
 
        # the test suite relies on the existence of this property
55
 
        self._method_name = proxy_method._method_name
56
 
        self._append = append
57
 
        self._block = block
58
 
 
59
 
    def __call__(self, *args, **keywords):
60
 
        if (keywords.has_key('reply_handler') or
61
 
            keywords.get('ignore_reply', False)):
62
 
            # defer the async call til introspection finishes
63
 
            self._append(self._proxy_method, args, keywords)
64
 
            return None
65
 
        else:
66
 
            # we're being synchronous, so block
67
 
            self._block()
68
 
            return self._proxy_method(*args, **keywords)
69
 
 
70
 
    def call_async(self, *args, **keywords):
71
 
        self._append(self._proxy_method, args, keywords)
72
 
 
73
 
 
74
 
class _ProxyMethod:
75
 
    """A proxy method.
76
 
 
77
 
    Typically a member of a ProxyObject. Calls to the
78
 
    method produce messages that travel over the Bus and are routed
79
 
    to a specific named Service.
80
 
    """
81
 
    def __init__(self, proxy, connection, bus_name, object_path, method_name,
82
 
                 iface):
83
 
        if object_path == LOCAL_PATH:
84
 
            raise DBusException('Methods may not be called on the reserved '
85
 
                                'path %s' % LOCAL_PATH)
86
 
 
87
 
        # trust that the proxy, and the properties it had, are OK
88
 
        self._proxy          = proxy
89
 
        self._connection     = connection
90
 
        self._named_service  = bus_name
91
 
        self._object_path    = object_path
92
 
        # fail early if the method name is bad
93
 
        _dbus_bindings.validate_member_name(method_name)
94
 
        # the test suite relies on the existence of this property
95
 
        self._method_name    = method_name
96
 
        # fail early if the interface name is bad
97
 
        if iface is not None:
98
 
            _dbus_bindings.validate_interface_name(iface)
99
 
        self._dbus_interface = iface
100
 
 
101
 
    def __call__(self, *args, **keywords):
102
 
        reply_handler = keywords.pop('reply_handler', None)
103
 
        error_handler = keywords.pop('error_handler', None)
104
 
        ignore_reply = keywords.pop('ignore_reply', False)
105
 
        signature = keywords.pop('signature', None)
106
 
 
107
 
        if reply_handler is not None or error_handler is not None:
108
 
            if reply_handler is None:
109
 
                raise MissingReplyHandlerException()
110
 
            elif error_handler is None:
111
 
                raise MissingErrorHandlerException()
112
 
            elif ignore_reply:
113
 
                raise TypeError('ignore_reply and reply_handler cannot be '
114
 
                                'used together')
115
 
 
116
 
        dbus_interface = keywords.pop('dbus_interface', self._dbus_interface)
117
 
 
118
 
        if signature is None:
119
 
            if dbus_interface is None:
120
 
                key = self._method_name
121
 
            else:
122
 
                key = dbus_interface + '.' + self._method_name
123
 
 
124
 
            signature = self._proxy._introspect_method_map.get(key, None)
125
 
 
126
 
        if ignore_reply or reply_handler is not None:
127
 
            self._connection.call_async(self._named_service,
128
 
                                        self._object_path,
129
 
                                        dbus_interface,
130
 
                                        self._method_name,
131
 
                                        signature,
132
 
                                        args,
133
 
                                        reply_handler,
134
 
                                        error_handler,
135
 
                                        **keywords)
136
 
        else:
137
 
            return self._connection.call_blocking(self._named_service,
138
 
                                                  self._object_path,
139
 
                                                  dbus_interface,
140
 
                                                  self._method_name,
141
 
                                                  signature,
142
 
                                                  args,
143
 
                                                  **keywords)
144
 
 
145
 
    def call_async(self, *args, **keywords):
146
 
        reply_handler = keywords.pop('reply_handler', None)
147
 
        error_handler = keywords.pop('error_handler', None)
148
 
        signature = keywords.pop('signature', None)
149
 
 
150
 
        dbus_interface = keywords.pop('dbus_interface', self._dbus_interface)
151
 
 
152
 
        if signature is None:
153
 
            if dbus_interface:
154
 
                key = dbus_interface + '.' + self._method_name
155
 
            else:
156
 
                key = self._method_name
157
 
            signature = self._proxy._introspect_method_map.get(key, None)
158
 
 
159
 
        self._connection.call_async(self._named_service,
160
 
                                    self._object_path,
161
 
                                    dbus_interface,
162
 
                                    self._method_name,
163
 
                                    signature,
164
 
                                    args,
165
 
                                    reply_handler,
166
 
                                    error_handler,
167
 
                                    **keywords)
168
 
 
169
 
 
170
 
class ProxyObject(object):
171
 
    """A proxy to the remote Object.
172
 
 
173
 
    A ProxyObject is provided by the Bus. ProxyObjects
174
 
    have member functions, and can be called like normal Python objects.
175
 
    """
176
 
    ProxyMethodClass = _ProxyMethod
177
 
    DeferredMethodClass = _DeferredMethod
178
 
 
179
 
    INTROSPECT_STATE_DONT_INTROSPECT = 0
180
 
    INTROSPECT_STATE_INTROSPECT_IN_PROGRESS = 1
181
 
    INTROSPECT_STATE_INTROSPECT_DONE = 2
182
 
 
183
 
    def __init__(self, conn=None, bus_name=None, object_path=None,
184
 
                 introspect=True, follow_name_owner_changes=False, **kwargs):
185
 
        """Initialize the proxy object.
186
 
 
187
 
        :Parameters:
188
 
            `conn` : `dbus.connection.Connection`
189
 
                The bus or connection on which to find this object.
190
 
                The keyword argument `bus` is a deprecated alias for this.
191
 
            `bus_name` : str
192
 
                A bus name for the application owning the object, to be used
193
 
                as the destination for method calls and the sender for
194
 
                signal matches. The keyword argument ``named_service`` is a
195
 
                deprecated alias for this.
196
 
            `object_path` : str
197
 
                The object path at which the application exports the object
198
 
            `introspect` : bool
199
 
                If true (default), attempt to introspect the remote
200
 
                object to find out supported methods and their signatures
201
 
            `follow_name_owner_changes` : bool
202
 
                If true (default is false) and the `bus_name` is a
203
 
                well-known name, follow ownership changes for that name
204
 
        """
205
 
        bus = kwargs.pop('bus', None)
206
 
        if bus is not None:
207
 
            if conn is not None:
208
 
                raise TypeError('conn and bus cannot both be specified')
209
 
            conn = bus
210
 
            from warnings import warn
211
 
            warn('Passing the bus parameter to ProxyObject by name is '
212
 
                 'deprecated: please use positional parameters',
213
 
                 DeprecationWarning, stacklevel=2)
214
 
        named_service = kwargs.pop('named_service', None)
215
 
        if named_service is not None:
216
 
            if bus_name is not None:
217
 
                raise TypeError('bus_name and named_service cannot both be '
218
 
                                'specified')
219
 
            bus_name = named_service
220
 
            from warnings import warn
221
 
            warn('Passing the named_service parameter to ProxyObject by name '
222
 
                 'is deprecated: please use positional parameters',
223
 
                 DeprecationWarning, stacklevel=2)
224
 
        if kwargs:
225
 
            raise TypeError('ProxyObject.__init__ does not take these '
226
 
                            'keyword arguments: %s'
227
 
                            % ', '.join(kwargs.iterkeys()))
228
 
 
229
 
        if follow_name_owner_changes:
230
 
            # we don't get the signals unless the Bus has a main loop
231
 
            # XXX: using Bus internals
232
 
            conn._require_main_loop()
233
 
 
234
 
        self._bus = conn
235
 
 
236
 
        if bus_name is not None:
237
 
            _dbus_bindings.validate_bus_name(bus_name)
238
 
        # the attribute is still called _named_service for the moment,
239
 
        # for the benefit of telepathy-python
240
 
        self._named_service = self._requested_bus_name = bus_name
241
 
 
242
 
        _dbus_bindings.validate_object_path(object_path)
243
 
        self.__dbus_object_path__ = object_path
244
 
 
245
 
        if not follow_name_owner_changes:
246
 
            self._named_service = conn.activate_name_owner(bus_name)
247
 
 
248
 
        #PendingCall object for Introspect call
249
 
        self._pending_introspect = None
250
 
        #queue of async calls waiting on the Introspect to return
251
 
        self._pending_introspect_queue = []
252
 
        #dictionary mapping method names to their input signatures
253
 
        self._introspect_method_map = {}
254
 
 
255
 
        # must be a recursive lock because block() is called while locked,
256
 
        # and calls the callback which re-takes the lock
257
 
        self._introspect_lock = RLock()
258
 
 
259
 
        if not introspect or self.__dbus_object_path__ == LOCAL_PATH:
260
 
            self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
261
 
        else:
262
 
            self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS
263
 
 
264
 
            self._pending_introspect = self._Introspect()
265
 
 
266
 
    bus_name = property(lambda self: self._named_service, None, None,
267
 
            """The bus name to which this proxy is bound. (Read-only,
268
 
            may change.)
269
 
 
270
 
            If the proxy was instantiated using a unique name, this property
271
 
            is that unique name.
272
 
 
273
 
            If the proxy was instantiated with a well-known name and with
274
 
            ``follow_name_owner_changes`` set false (the default), this
275
 
            property is the unique name of the connection that owned that
276
 
            well-known name when the proxy was instantiated, which might
277
 
            not actually own the requested well-known name any more.
278
 
 
279
 
            If the proxy was instantiated with a well-known name and with
280
 
            ``follow_name_owner_changes`` set true, this property is that
281
 
            well-known name.
282
 
            """)
283
 
 
284
 
    requested_bus_name = property(lambda self: self._requested_bus_name,
285
 
            None, None,
286
 
            """The bus name which was requested when this proxy was
287
 
            instantiated.
288
 
            """)
289
 
 
290
 
    object_path = property(lambda self: self.__dbus_object_path__,
291
 
            None, None,
292
 
            """The object-path of this proxy.""")
293
 
 
294
 
    # XXX: We don't currently support this because it's the signal receiver
295
 
    # that's responsible for tracking name owner changes, but it
296
 
    # seems a natural thing to add in future.
297
 
    #unique_bus_name = property(lambda self: something, None, None,
298
 
    #        """The unique name of the connection to which this proxy is
299
 
    #        currently bound. (Read-only, may change.)
300
 
    #        """)
301
 
 
302
 
    def connect_to_signal(self, signal_name, handler_function, dbus_interface=None, **keywords):
303
 
        """Arrange for the given function to be called when the given signal
304
 
        is received.
305
 
 
306
 
        :Parameters:
307
 
            `signal_name` : str
308
 
                The name of the signal
309
 
            `handler_function` : callable
310
 
                A function to be called when the signal is emitted by
311
 
                the remote object. Its positional arguments will be the
312
 
                arguments of the signal; optionally, it may be given
313
 
                keyword arguments as described below.
314
 
            `dbus_interface` : str
315
 
                Optional interface with which to qualify the signal name.
316
 
                If None (the default) the handler will be called whenever a
317
 
                signal of the given member name is received, whatever
318
 
                its interface.
319
 
        :Keywords:
320
 
            `utf8_strings` : bool
321
 
                If True, the handler function will receive any string
322
 
                arguments as dbus.UTF8String objects (a subclass of str
323
 
                guaranteed to be UTF-8). If False (default) it will receive
324
 
                any string arguments as dbus.String objects (a subclass of
325
 
                unicode).
326
 
            `byte_arrays` : bool
327
 
                If True, the handler function will receive any byte-array
328
 
                arguments as dbus.ByteArray objects (a subclass of str).
329
 
                If False (default) it will receive any byte-array
330
 
                arguments as a dbus.Array of dbus.Byte (subclasses of:
331
 
                a list of ints).
332
 
            `sender_keyword` : str
333
 
                If not None (the default), the handler function will receive
334
 
                the unique name of the sending endpoint as a keyword
335
 
                argument with this name
336
 
            `destination_keyword` : str
337
 
                If not None (the default), the handler function will receive
338
 
                the bus name of the destination (or None if the signal is a
339
 
                broadcast, as is usual) as a keyword argument with this name.
340
 
            `interface_keyword` : str
341
 
                If not None (the default), the handler function will receive
342
 
                the signal interface as a keyword argument with this name.
343
 
            `member_keyword` : str
344
 
                If not None (the default), the handler function will receive
345
 
                the signal name as a keyword argument with this name.
346
 
            `path_keyword` : str
347
 
                If not None (the default), the handler function will receive
348
 
                the object-path of the sending object as a keyword argument
349
 
                with this name
350
 
            `message_keyword` : str
351
 
                If not None (the default), the handler function will receive
352
 
                the `dbus.lowlevel.SignalMessage` as a keyword argument with
353
 
                this name.
354
 
            `arg...` : unicode or UTF-8 str
355
 
                If there are additional keyword parameters of the form
356
 
                ``arg``\ *n*, match only signals where the *n*\ th argument
357
 
                is the value given for that keyword parameter. As of this time
358
 
                only string arguments can be matched (in particular,
359
 
                object paths and signatures can't).
360
 
        """
361
 
        return \
362
 
        self._bus.add_signal_receiver(handler_function,
363
 
                                      signal_name=signal_name,
364
 
                                      dbus_interface=dbus_interface,
365
 
                                      bus_name=self._named_service,
366
 
                                      path=self.__dbus_object_path__,
367
 
                                      **keywords)
368
 
 
369
 
    def _Introspect(self):
370
 
        return self._bus.call_async(self._named_service,
371
 
                                    self.__dbus_object_path__,
372
 
                                    INTROSPECTABLE_IFACE, 'Introspect', '', (),
373
 
                                    self._introspect_reply_handler,
374
 
                                    self._introspect_error_handler,
375
 
                                    utf8_strings=True,
376
 
                                    require_main_loop=False)
377
 
 
378
 
    def _introspect_execute_queue(self):
379
 
        # FIXME: potential to flood the bus
380
 
        # We should make sure mainloops all have idle handlers
381
 
        # and do one message per idle
382
 
        for (proxy_method, args, keywords) in self._pending_introspect_queue:
383
 
            proxy_method(*args, **keywords)
384
 
        self._pending_introspect_queue = []
385
 
 
386
 
    def _introspect_reply_handler(self, data):
387
 
        self._introspect_lock.acquire()
388
 
        try:
389
 
            try:
390
 
                self._introspect_method_map = process_introspection_data(data)
391
 
            except IntrospectionParserException as e:
392
 
                self._introspect_error_handler(e)
393
 
                return
394
 
 
395
 
            self._introspect_state = self.INTROSPECT_STATE_INTROSPECT_DONE
396
 
            self._pending_introspect = None
397
 
            self._introspect_execute_queue()
398
 
        finally:
399
 
            self._introspect_lock.release()
400
 
 
401
 
    def _introspect_error_handler(self, error):
402
 
        logging.basicConfig()
403
 
        _logger.error("Introspect error on %s:%s: %s.%s: %s",
404
 
                      self._named_service, self.__dbus_object_path__,
405
 
                      error.__class__.__module__, error.__class__.__name__,
406
 
                      error)
407
 
        self._introspect_lock.acquire()
408
 
        try:
409
 
            _logger.debug('Executing introspect queue due to error')
410
 
            self._introspect_state = self.INTROSPECT_STATE_DONT_INTROSPECT
411
 
            self._pending_introspect = None
412
 
            self._introspect_execute_queue()
413
 
        finally:
414
 
            self._introspect_lock.release()
415
 
 
416
 
    def _introspect_block(self):
417
 
        self._introspect_lock.acquire()
418
 
        try:
419
 
            if self._pending_introspect is not None:
420
 
                self._pending_introspect.block()
421
 
            # else someone still has a _DeferredMethod from before we
422
 
            # finished introspection: no need to do anything special any more
423
 
        finally:
424
 
            self._introspect_lock.release()
425
 
 
426
 
    def _introspect_add_to_queue(self, callback, args, kwargs):
427
 
        self._introspect_lock.acquire()
428
 
        try:
429
 
            if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS:
430
 
                self._pending_introspect_queue.append((callback, args, kwargs))
431
 
            else:
432
 
                # someone still has a _DeferredMethod from before we
433
 
                # finished introspection
434
 
                callback(*args, **kwargs)
435
 
        finally:
436
 
            self._introspect_lock.release()
437
 
 
438
 
    def __getattr__(self, member):
439
 
        if member.startswith('__') and member.endswith('__'):
440
 
            raise AttributeError(member)
441
 
        else:
442
 
            return self.get_dbus_method(member)
443
 
 
444
 
    def get_dbus_method(self, member, dbus_interface=None):
445
 
        """Return a proxy method representing the given D-Bus method. The
446
 
        returned proxy method can be called in the usual way. For instance, ::
447
 
 
448
 
            proxy.get_dbus_method("Foo", dbus_interface='com.example.Bar')(123)
449
 
 
450
 
        is equivalent to::
451
 
 
452
 
            proxy.Foo(123, dbus_interface='com.example.Bar')
453
 
 
454
 
        or even::
455
 
 
456
 
            getattr(proxy, "Foo")(123, dbus_interface='com.example.Bar')
457
 
 
458
 
        However, using `get_dbus_method` is the only way to call D-Bus
459
 
        methods with certain awkward names - if the author of a service
460
 
        implements a method called ``connect_to_signal`` or even
461
 
        ``__getattr__``, you'll need to use `get_dbus_method` to call them.
462
 
 
463
 
        For services which follow the D-Bus convention of CamelCaseMethodNames
464
 
        this won't be a problem.
465
 
        """
466
 
 
467
 
        ret = self.ProxyMethodClass(self, self._bus,
468
 
                                    self._named_service,
469
 
                                    self.__dbus_object_path__, member,
470
 
                                    dbus_interface)
471
 
 
472
 
        # this can be done without taking the lock - the worst that can
473
 
        # happen is that we accidentally return a _DeferredMethod just after
474
 
        # finishing introspection, in which case _introspect_add_to_queue and
475
 
        # _introspect_block will do the right thing anyway
476
 
        if self._introspect_state == self.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS:
477
 
            ret = self.DeferredMethodClass(ret, self._introspect_add_to_queue,
478
 
                                           self._introspect_block)
479
 
 
480
 
        return ret
481
 
 
482
 
    def __repr__(self):
483
 
        return '<ProxyObject wrapping %s %s %s at %#x>'%(
484
 
            self._bus, self._named_service, self.__dbus_object_path__, id(self))
485
 
    __str__ = __repr__
486
 
 
487
 
 
488
 
class Interface(object):
489
 
    """An interface into a remote object.
490
 
 
491
 
    An Interface can be used to wrap ProxyObjects
492
 
    so that calls can be routed to their correct
493
 
    D-Bus interface.
494
 
    """
495
 
 
496
 
    def __init__(self, object, dbus_interface):
497
 
        """Construct a proxy for the given interface on the given object.
498
 
 
499
 
        :Parameters:
500
 
            `object` : `dbus.proxies.ProxyObject` or `dbus.Interface`
501
 
                The remote object or another of its interfaces
502
 
            `dbus_interface` : str
503
 
                An interface the `object` implements
504
 
        """
505
 
        if isinstance(object, Interface):
506
 
            self._obj = object.proxy_object
507
 
        else:
508
 
            self._obj = object
509
 
        self._dbus_interface = dbus_interface
510
 
 
511
 
    object_path = property (lambda self: self._obj.object_path, None, None,
512
 
                            "The D-Bus object path of the underlying object")
513
 
    __dbus_object_path__ = object_path
514
 
    bus_name = property (lambda self: self._obj.bus_name, None, None,
515
 
                         "The bus name to which the underlying proxy object "
516
 
                         "is bound")
517
 
    requested_bus_name = property (lambda self: self._obj.requested_bus_name,
518
 
                                   None, None,
519
 
                                   "The bus name which was requested when the "
520
 
                                   "underlying object was created")
521
 
    proxy_object = property (lambda self: self._obj, None, None,
522
 
                             """The underlying proxy object""")
523
 
    dbus_interface = property (lambda self: self._dbus_interface, None, None,
524
 
                               """The D-Bus interface represented""")
525
 
 
526
 
    def connect_to_signal(self, signal_name, handler_function,
527
 
                          dbus_interface=None, **keywords):
528
 
        """Arrange for a function to be called when the given signal is
529
 
        emitted.
530
 
 
531
 
        The parameters and keyword arguments are the same as for
532
 
        `dbus.proxies.ProxyObject.connect_to_signal`, except that if
533
 
        `dbus_interface` is None (the default), the D-Bus interface that
534
 
        was passed to the `Interface` constructor is used.
535
 
        """
536
 
        if not dbus_interface:
537
 
            dbus_interface = self._dbus_interface
538
 
 
539
 
        return self._obj.connect_to_signal(signal_name, handler_function,
540
 
                                           dbus_interface, **keywords)
541
 
 
542
 
    def __getattr__(self, member):
543
 
        if member.startswith('__') and member.endswith('__'):
544
 
            raise AttributeError(member)
545
 
        else:
546
 
            return self._obj.get_dbus_method(member, self._dbus_interface)
547
 
 
548
 
    def get_dbus_method(self, member, dbus_interface=None):
549
 
        """Return a proxy method representing the given D-Bus method.
550
 
 
551
 
        This is the same as `dbus.proxies.ProxyObject.get_dbus_method`
552
 
        except that if `dbus_interface` is None (the default),
553
 
        the D-Bus interface that was passed to the `Interface` constructor
554
 
        is used.
555
 
        """
556
 
        if dbus_interface is None:
557
 
            dbus_interface = self._dbus_interface
558
 
        return self._obj.get_dbus_method(member, dbus_interface)
559
 
 
560
 
    def __repr__(self):
561
 
        return '<Interface %r implementing %r at %#x>'%(
562
 
        self._obj, self._dbus_interface, id(self))
563
 
    __str__ = __repr__