Issues (838)

tcod/tcod.py (3 issues)

1
"""This module focuses on improvements to the Python libtcod API.
2
"""
3
from __future__ import absolute_import as _
4
5
import sys as _sys
6
7
import warnings
8
9
from tcod.libtcod import lib, ffi, BKGND_DEFAULT, BKGND_SET
0 ignored issues
show
Unused BKGND_DEFAULT imported from tcod.libtcod
Loading history...
Unused BKGND_SET imported from tcod.libtcod
Loading history...
Unused lib imported from tcod.libtcod
Loading history...
10
11
12
def _unpack_char_p(char_p):
13
    if char_p == ffi.NULL:
14
        return ''
15
    return ffi.string(char_p).decode()
16
17
18
def _int(int_or_str):
19
    'return an integer where a single character string may be expected'
20
    if isinstance(int_or_str, str):
21
        return ord(int_or_str)
22
    if isinstance(int_or_str, bytes):
23
        return int_or_str[0]
24
    return int(int_or_str) # check for __count__
25
26
27
if _sys.version_info[0] == 2: # Python 2
28
    def _bytes(string):
29
        if isinstance(string, unicode):
30
            return string.encode()
31
        return string
32
33
    def _unicode(string):
34
        if not isinstance(string, unicode):
35
            return string.decode('latin-1')
36
        return string
37
38
else: # Python 3
39
    def _bytes(string):
40
        if isinstance(string, str):
41
            return string.encode()
42
        return string
43
44
    def _unicode(string):
45
        if isinstance(string, bytes):
46
            return string.decode('latin-1')
47
        return string
48
49
50
def _fmt_bytes(string):
51
    return _bytes(string).replace(b'%', b'%%')
52
53
def _fmt_unicode(string):
54
    return _unicode(string).replace(u'%', u'%%')
55
56
57
class _PropagateException():
58
    """ context manager designed to propagate exceptions outside of a cffi
59
    callback context.  normally cffi suppresses the exception
60
61
    when propagate is called this class will hold onto the error until the
62
    control flow leaves the context, then the error will be raised
63
64
    with _PropagateException as propagate:
65
    # give propagate as onerror parameter for ffi.def_extern
66
    """
67
68
    def __init__(self):
69
        self.exc_info = None # (exception, exc_value, traceback)
70
71
    def propagate(self, *exc_info):
72
        """ set an exception to be raised once this context exits
73
74
        if multiple errors are caught, only keep the first exception raised
75
        """
76
        if not self.exc_info:
77
            self.exc_info = exc_info
78
79
    def __enter__(self):
80
        """ once in context, only the propagate call is needed to use this
81
        class effectively
82
        """
83
        return self.propagate
84
85
    def __exit__(self, type, value, traceback):
86
        """ if we're holding on to an exception, raise it now
87
88
        prefers our held exception over any current raising error
89
90
        self.exc_info is reset now in case of nested manager shenanigans
91
        """
92
        if self.exc_info:
93
            type, value, traceback = self.exc_info
94
            self.exc_info = None
95
        if type:
96
            # Python 2/3 compatible throw
97
            exception = type(value)
98
            exception.__traceback__ = traceback
99
            raise exception
100
101
102
class _CDataWrapper(object):
103
104
    def __init__(self, *args, **kargs):
105
        self.cdata = self._get_cdata_from_args(*args, **kargs)
106
        if self.cdata == None:
107
            self.cdata = ffi.NULL
108
        super(_CDataWrapper, self).__init__()
109
110
    @staticmethod
111
    def _get_cdata_from_args(*args, **kargs):
112
        if len(args) == 1 and isinstance(args[0], ffi.CData) and not kargs:
113
            return args[0]
114
        else:
115
            return None
116
117
118
    def __hash__(self):
119
        return hash(self.cdata)
120
121
    def __eq__(self, other):
122
        try:
123
            return self.cdata == other.cdata
124
        except AttributeError:
125
            return NotImplemented
126
127
    def __getattr__(self, attr):
128
        if 'cdata' in self.__dict__:
129
            return getattr(self.__dict__['cdata'], attr)
130
        raise AttributeError(attr)
131
132
    def __setattr__(self, attr, value):
133
        if hasattr(self, 'cdata') and hasattr(self.cdata, attr):
134
            setattr(self.cdata, attr, value)
135
        else:
136
            super(_CDataWrapper, self).__setattr__(attr, value)
137
138
139
def _console(console):
140
    """Return a cffi console."""
141
    try:
142
        return console.console_c
143
    except AttributeError:
144
        warnings.warn(
145
            ("Falsy console parameters are deprecated, "
146
             "always use a console instance."),
147
            DeprecationWarning,
148
            stacklevel=2,
149
            )
150
        return ffi.NULL
151