Completed
Push — docs ( e5b7b4...013701 )
by Kyle
01:17
created

Color._init()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
1
"""This module focuses on improvements to the Python libtcod API.
2
"""
3
from __future__ import absolute_import as _
4
5
import os as _os
0 ignored issues
show
Unused Code introduced by
Unused os imported as _os
Loading history...
6
import sys as _sys
7
8
import platform as _platform
0 ignored issues
show
Unused Code introduced by
Unused platform imported as _platform
Loading history...
9
import weakref as _weakref
10
import functools as _functools
11
12
def _unpack_char_p(char_p):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
13
    if char_p == ffi.NULL:
14
        return ''
15
    return ffi.string(char_p).decode()
16
17
def _int(int_or_str):
18
    'return an integer where a single character string may be expected'
19
    if isinstance(int_or_str, str):
20
        return ord(int_or_str)
21
    if isinstance(int_or_str, bytes):
22
        return int_or_str[0]
23
    return int(int_or_str) # check for __count__
24
25
def _cdata(cdata):
26
    """covert value into a cffi.CData instance"""
27
    try: # first check for _CDataWrapper
28
        cdata = cdata.cdata
29
    except AttributeError: # assume cdata is valid
0 ignored issues
show
Unused Code introduced by
This except handler seems to be unused and could be removed.

Except handlers which only contain pass and do not have an else clause can usually simply be removed:

try:
    raises_exception()
except:  # Could be removed
    pass
Loading history...
30
        pass
31
    if cdata is None: # convert None to NULL
32
        cdata = ffi.NULL
33
    return cdata
34
35
def _color(color):
36
    """convert value to a TCOD_colot_t compatible type"""
37
    try:
38
        if len(color) == 3:
39
            return color
40
    except TypeError:
0 ignored issues
show
Unused Code introduced by
This except handler seems to be unused and could be removed.

Except handlers which only contain pass and do not have an else clause can usually simply be removed:

try:
    raises_exception()
except:  # Could be removed
    pass
Loading history...
41
        pass
42
    return tuple(Color(color))
43
44
if _sys.version_info[0] == 2: # Python 2
45
    def _bytes(string):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
46
        if isinstance(string, unicode):
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'unicode'
Loading history...
47
            return string.encode()
48
        return string
49
50
    def _unicode(string):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
51
        if not isinstance(string, unicode):
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'unicode'
Loading history...
52
            return string.decode()
53
        return string
54
55
else: # Python 3
56
    def _bytes(string):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
57
        if isinstance(string, str):
58
            return string.encode()
59
        return string
60
61
    def _unicode(string):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
62
        if isinstance(string, bytes):
63
            return string.decode()
64
        return string
65
66
class _PropagateException():
67
    """ context manager designed to propagate exceptions outside of a cffi
68
    callback context.  normally cffi suppresses the exception
69
70
    when propagate is called this class will hold onto the error until the
71
    control flow leaves the context, then the error will be raised
72
73
    with _PropagateException as propagate:
74
    # give propagate as onerror parameter for ffi.def_extern
75
    """
76
77
    def __init__(self):
78
        self.exc_info = None # (exception, exc_value, traceback)
79
80
    def propagate(self, *exc_info):
81
        """ set an exception to be raised once this context exits
82
83
        if multiple errors are caught, only keep the first exception raised
84
        """
85
        if not self.exc_info:
86
            self.exc_info = exc_info
87
88
    def __enter__(self):
89
        """ once in context, only the propagate call is needed to use this
90
        class effectively
91
        """
92
        return self.propagate
93
94
    def __exit__(self, type, value, traceback):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in type.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
95
        """ if we're holding on to an exception, raise it now
96
97
        prefers our held exception over any current raising error
98
99
        self.exc_info is reset now in case of nested manager shenanigans
100
        """
101
        if self.exc_info:
102
            type, value, traceback = self.exc_info
0 ignored issues
show
Bug introduced by
The tuple unpacking with sequence seems to be unbalanced; 3 value(s) for 0 label(s)

This happens when the amount of values does not equal the amount of labels:

a, b = ("a", "b", "c")  # only 2 labels for 3 values
Loading history...
Bug Best Practice introduced by
It seems like you are trying to unpack a non-sequence, which was defined at line 78.
Loading history...
Bug Best Practice introduced by
It seems like you are trying to unpack a non-sequence, which was defined at line 103.
Loading history...
103
            self.exc_info = None
104
        if type:
105
            # Python 2/3 compatible throw
106
            exception = type(value)
107
            exception.__traceback__ = traceback
108
            raise exception
109
110
class _CDataWrapper(object):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
111
112
    def __init__(self, *args, **kargs):
113
        self.cdata = self._get_cdata_from_args(*args, **kargs)
114
        if self.cdata == None:
115
            self.cdata = ffi.NULL
116
        super(_CDataWrapper, self).__init__()
117
118
    def _get_cdata_from_args(self, *args, **kargs):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
119
        if len(args) == 1 and isinstance(args[0], ffi.CData) and not kargs:
120
            return args[0]
121
        else:
122
            return None
123
124
125
    def __hash__(self):
126
        return hash(self.cdata)
127
128
    def __eq__(self, other):
129
        try:
130
            return self.cdata == other.cdata
131
        except AttributeError:
132
            return NotImplemented
133
134
    def __getattr__(self, attr):
135
        if 'cdata' in self.__dict__:
136
            return getattr(self.__dict__['cdata'], attr)
137
        raise AttributeError(attr)
138
139
    def __setattr__(self, attr, value):
140
        if hasattr(self, 'cdata') and hasattr(self.cdata, attr):
141
            setattr(self.cdata, attr, value)
142
        else:
143
            super(_CDataWrapper, self).__setattr__(attr, value)
144
145
def _assert_cdata_is_not_null(func):
146
    """Any BSP methods which use a cdata object in a TCOD call need to have
147
    a sanity check, otherwise it may end up passing a NULL pointer"""
148
    if __debug__:
149
        @_functools.wraps(func)
150
        def check_sanity(*args, **kargs):
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Unused Code introduced by
The variable check_sanity seems to be unused.
Loading history...
151
            assert self.cdata != ffi.NULL and self.cdata is not None, \
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'self'
Loading history...
152
                   'cannot use function, cdata is %r' % self.cdata
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'self'
Loading history...
153
            return func(*args, **kargs)
154
    return func
155
156
class BSP(_CDataWrapper):
157
    """
158
159
    .. attribute:: x
160
    .. attribute:: y
161
    .. attribute:: w
162
    .. attribute:: h
163
164
    :param int x: rectangle left coordinate
165
    :param int y: rectangle top coordinate
166
    :param int w: rectangle width
167
    :param int h: rectangle height
168
169
    .. versionchanged:: 2.0
170
       You can create BSP's with this class contructor instead of using
171
       :any:`bsp_new_with_size`.
172
173
    """
174
175
    def __init__(self, *args, **kargs):
176
        self._reference = None # to prevent garbage collection
177
        self._children = _weakref.WeakSet() # used by _invalidate_children
178
        super(BSP, self).__init__(*args, **kargs)
179
        if self._get_cdata_from_args(*args, **kargs) is None:
180
            self._init(*args, **kargs)
181
182
    def _init(self, x, y, w, h):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
183
        self.cdata = ffi.gc(lib.TCOD_bsp_new_with_size(x, y, w, h),
184
                             lib.TCOD_bsp_delete)
185
186
    def _pass_reference(self, reference):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
187
        self._reference = reference
188
        self._reference._children.add(self)
189
        return self
190
191
    def _invalidate_children(self):
192
        """Invalidates BSP instances known to be based off of this one."""
193
        for child in self._children:
194
            child._reference = None
195
            child._invalidate_children()
196
            child.cdata = ffi.NULL
197
        self._children.clear()
198
199
    def __repr__(self):
200
        """Provide a useful readout when printed."""
201
        if not self.cdata:
202
            return '<%s NULL!>' % self.__class__.__name__
203
204
        status = 'leaf'
205
        if not self.is_leaf():
206
            status = ('split at dicision=%i,orientation=%r' %
207
                      (self.get_division(), self.get_orientation()))
208
209
        return ('<%s(x=%i,y=%i,w=%i,h=%i)depth=%i,%s>' %
210
                (self.__class__.__name__,
211
                 self.x, self.y, self.w, self.h, self.get_depth(), status))
212
213
    def get_depth(self):
214
        """Return the depth of this node.
215
216
        :rtype: int
217
218
        .. versionadded:: 2.0
219
        """
220
        return self.cdata.level
221
222
    def get_division(self):
223
        """Return the point where this node was divided into parts.
224
225
        :rtype: :any:`int` or :any:`None`
226
227
        .. versionadded:: 2.0
228
        """
229
        if self.is_leaf():
230
            return None
231
        return self.cdata.position
232
233
    def get_orientation(self):
234
        """
235
236
        :rtype: str
237
238
        .. versionadded:: 2.0
239
        """
240
        if self.is_leaf():
241
            return ''
242
        elif self.cdata.horizontal:
243
            return 'horizontal'
244
        else:
245
            return 'vertical'
246
247
    @_assert_cdata_is_not_null
248
    def split_once(self, orientation, position):
249
        """
250
251
        :rtype: tuple
252
253
        .. versionadded:: 2.0
254
        """
255
        # orientation = horz
256
        if orientation[:1].lower() == 'h':
257
            lib.TCOD_bsp_split_once(self.cdata, True, position)
258
        elif orientation[:1].lower() == 'v':
259
            lib.TCOD_bsp_split_once(self.cdata, False, position)
260
        else:
261
            raise ValueError("orientation must be 'horizontal' or 'vertical'"
262
                             "\nNot %r" % orientation)
263
        return self.get_children()
264
265
    @_assert_cdata_is_not_null
266
    def split_recursive(self, depth, min_width, min_height,
267
                        max_horz_ratio, max_vert_raito, random=None):
268
        """
269
270
        :rtype: iter
271
272
        .. versionadded:: 2.0
273
        """
274
        lib.TCOD_bsp_split_recursive(self.cdata, random or ffi.NULL,
275
                                      depth, min_width, min_height,
276
                                      max_horz_ratio, max_vert_raito)
277
        return self.walk()
278
279
    @_assert_cdata_is_not_null
280
    def resize(self, x, y, w, h):
281
        """Resize this BSP to the provided rectangle.
282
283
        :param int x: rectangle left coordinate
284
        :param int y: rectangle top coordinate
285
        :param int w: rectangle width
286
        :param int h: rectangle height
287
288
        .. versionadded:: 2.0
289
        """
290
        lib.TCOD_bsp_resize(self.cdata, x, y, w, h)
291
292
    @_assert_cdata_is_not_null
293
    def get_left(self):
294
        """Return this BSP's 'left' child.
295
296
        Returns None if this BSP is a leaf node.
297
298
        :return: BSP's left/top child or None.
299
        :rtype: :any:`BSP` or :any:`None`
300
301
        .. versionadded:: 2.0
302
        """
303
        if self.is_leaf():
304
            return None
305
        return BSP(lib.TCOD_bsp_left(self.cdata))._pass_reference(self)
306
307
    @_assert_cdata_is_not_null
308
    def get_right(self):
309
        """Return this BSP's 'right' child.
310
311
        Returns None if this BSP is a leaf node.
312
313
        :return: BSP's right/bottom child or None.
314
        :rtype: :any:`BSP` or :any:`None`
315
316
        .. versionadded:: 2.0
317
        """
318
        if self.is_leaf():
319
            return None
320
        return BSP(lib.TCOD_bsp_right(self.cdata))._pass_reference(self)
321
322
    @_assert_cdata_is_not_null
323
    def get_parent(self):
324
        """Return this BSP's parent node.
325
326
        :return: Returns the parent node as a BSP instance.
327
                 Returns None if this BSP has no parent.
328
        :rtype: :any:`BSP` or :any:`None`
329
330
        .. versionadded:: 2.0
331
        """
332
        node = BSP(lib.TCOD_bsp_father(self.cdata))._pass_reference(self)
333
        if node.cdata == ffi.NULL:
334
            return None
335
        return node
336
337
    @_assert_cdata_is_not_null
338
    def get_children(self):
339
        """Return as a tuple, this instances immediate children, if any.
340
341
        :return: Returns a tuple of (left, right) BSP instances.
342
                 The returned tuple is empty if this BSP has no children.
343
        :rtype: tuple
344
345
        .. versionadded:: 2.0
346
        """
347
        if self.is_leaf():
348
            return ()
349
        return (BSP(lib.TCOD_bsp_left(self.cdata))._pass_reference(self),
350
                BSP(lib.TCOD_bsp_right(self.cdata))._pass_reference(self))
351
352
    @_assert_cdata_is_not_null
353
    def walk(self):
354
        """Iterate over this BSP's hieracrhy.
355
356
        The iterator will include the instance which called it.
357
        It will traverse its own children and grandchildren, in no particular
358
        order.
359
360
        :return: Returns an iterator of BSP instances.
361
        :rtype: iter
362
363
        .. versionadded:: 2.0
364
        """
365
        for child in self.get_children():
366
            for grandchild in child.walk():
367
                yield grandchild
368
        yield self
369
370
    @_assert_cdata_is_not_null
371
    def is_leaf(self):
372
        """Returns True if this node is a leaf.  False when this node has children.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (83/79).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
373
374
        :rtype: bool
375
376
        .. versionadded:: 2.0
377
        """
378
        return bool(lib.TCOD_bsp_is_leaf(self.cdata))
379
380
    @_assert_cdata_is_not_null
381
    def contains(self, x, y):
382
        """Returns True if this node contains these coordinates.
383
384
        :rtype: bool
385
386
        .. versionadded:: 2.0
387
        """
388
        return bool(lib.TCOD_bsp_contains(self.cdata, x, y))
389
390
    @_assert_cdata_is_not_null
391
    def find_node(self, x, y):
392
        """Return the deepest node which contains these coordinates.
393
394
        :rtype: :any:`BSP` or :any:`None`
395
396
        .. versionadded:: 2.0
397
        """
398
        node = BSP(lib.TCOD_bsp_find_node(self.cdata,
399
                                           x, y))._pass_reference(self)
400
        if node.cdata == ffi.NULL:
401
            node = None
402
        return node
403
404
class HeightMap(_CDataWrapper):
405
    """libtcod HeightMap instance
406
    """
407
408
    def __init__(self, *args, **kargs):
409
        super(HeightMap, self).__init__(*args, **kargs)
410
        if not self.cdata:
411
            self._init(*args, **kargs)
412
413
    def _init(self, width, height):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
414
        self.cdata = ffi.gc(lib.TCOD_heightmap_new(width, height),
415
                             lib.TCOD_heightmap_delete)
416
417
418
class Color(_CDataWrapper):
419
    """list-like behaviour could change in the future"""
420
421
    def __init__(self, *args, **kargs):
422
        super(Color, self).__init__(*args, **kargs)
423
        if not self.cdata:
424
            try:
425
                self._init_from_color(*args, **kargs)
426
            except TypeError:
427
                self._init(*args, **kargs)
428
429
    def _init_from_color(self, color):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
430
        try:
431
            self._init(color.r, color.g, color.b)
432
        except AttributeError:
433
            raise TypeError()
434
435
    def _init(self, r=0, g=0, b=0):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
436
        self.cdata = ffi.new('TCOD_color_t*', (r, g, b))
437
438
    @classmethod
439
    def from_cdata(cls, tcod_color):
440
        """new in libtcod-cffi"""
441
        return cls(tcod_color.r, tcod_color.g, tcod_color.b)
442
443
444
    @classmethod
445
    def from_int(cls, integer):
446
        """a TDL int color: 0xRRGGBB
447
448
        new in libtcod-cffi"""
449
        return cls(lib.TDL_color_from_int(integer))
450
451
    def __eq__(self, other):
452
        return (isinstance(other, (Color)) and
453
                lib.TCOD_color_equals(_color(self), _color(other)))
454
455
    def __mul__(self, other):
456
        if isinstance(other, (Color, list, tuple)):
457
            return Color(lib.TCOD_color_multiply(_color(self),
458
                                                 _color(other)))
459
        else:
460
            return Color(lib.TCOD_color_multiply_scalar(_color(self),
461
                                                        _color(other)))
462
463
    def __add__(self, other):
464
        return Color(lib.TCOD_color_add(_color(self), _color(other)))
465
466
    def __sub__(self, other):
467
        return Color(lib.TCOD_color_subtract(_color(self), _color(other)))
468
469
    def __iter__(self):
470
        return iter((self.r, self.g, self.b))
471
472
    def __repr__(self):
473
        return "<%s(%i,%i,%i)>" % (self.__class__.__name__,
474
                                   self.r, self.g, self.b)
475
476
    def __iter__(self):
0 ignored issues
show
Bug introduced by
method already defined line 469
Loading history...
477
        return iter((self.cdata.r, self.cdata.g, self.cdata.b))
478
479
    def __int__(self):
480
        # new in libtcod-cffi
481
        return lib.TDL_color_RGB(*self)
482
483
484
class FrozenColor(Color):
485
    """new in libtcod-cffi"""
486
487
    @classmethod
488
    def from_cdata(cls, tcod_color):
489
        return cls(tcod_color)
490
        return cls(tcod_color.r, tcod_color.g, tcod_color.b)
0 ignored issues
show
Unused Code introduced by
This code does not seem to be reachable.
Loading history...
491
492
    @classmethod
493
    def from_int(cls, integer):
494
        return cls.from_cdata(lib.TDL_color_from_int(integer))
495
496
    def __hash__(self):
497
        return hash(tuple(self))
498
499
class Key(_CDataWrapper):
500
    """Key Event instance
501
    """
502
503
    def __init__(self, *args):
504
        super(Key, self).__init__(*args)
505
        if self.cdata == ffi.NULL:
506
            self.cdata = ffi.new('TCOD_key_t*')
507
508
    def __getattr__(self, attr):
509
        if attr == 'c':
510
            return ord(getattr(self.cdata, attr))
511
        else:
512
            return super(Key, self).__getattr__(attr)
513
514
class Mouse(_CDataWrapper):
515
    """Mouse event instance
516
    """
517
518
    def __init__(self, *args):
519
        super(Mouse, self).__init__(*args)
520
        if self.cdata == ffi.NULL:
521
            self.cdata = ffi.new('TCOD_mouse_t*')
522
523
524
def clipboard_set(string):
525
    """Set the clipboard contents to string.
526
527
    .. versionadded:: 2.0
528
    """
529
    lib.TCOD_sys_clipboard_set(_bytes(string))
530
531
def clipboard_get():
532
    """Return the current contents of the clipboard.
533
534
    .. versionadded:: 2.0
535
    """
536
    return _unpack_char_p(lib.TCOD_sys_clipboard_get())
537
538
from tcod.libtcod import *
0 ignored issues
show
Coding Style introduced by
The usage of wildcard imports like tcod.libtcod should generally be avoided.
Loading history...
Unused Code introduced by
NOISE_DEFAULT_LACUNARITY was imported with wildcard, but is not used.
Loading history...
Unused Code introduced by
BKGND_ALPHA was imported with wildcard, but is not used.
Loading history...
Unused Code introduced by
NOISE_DEFAULT_HURST was imported with wildcard, but is not used.
Loading history...
Unused Code introduced by
BKGND_ADDALPHA was imported with wildcard, but is not used.
Loading history...
Unused Code introduced by
FOV_PERMISSIVE was imported with wildcard, but is not used.
Loading history...
539
540
@ffi.def_extern()
541
def _pycall_bsp_callback(node, handle):
542
    """static bool _pycall_bsp_callback(TCOD_bsp_t *node, void *userData);"""
543
    func, userData, propagate = ffi.from_handle(handle)
544
    try:
545
        return func(BSP(node), userData)
546
    except BaseException:
547
        propagate(*_sys.exc_info())
548
        return False
549
550
551
__all__ = [_name for _name in list(globals()) if _name[0] != '_']
552