cython

Форк
0
/
Errors.py 
295 строк · 8.9 Кб
1
#
2
#   Errors
3
#
4

5
any_string_type = (bytes, str)
6

7
import sys
8
from contextlib import contextmanager
9

10
try:
11
    from threading import local as _threadlocal
12
except ImportError:
13
    class _threadlocal: pass
14

15
threadlocal = _threadlocal()
16

17
from ..Utils import open_new_file
18
from . import DebugFlags
19
from . import Options
20

21

22
class PyrexError(Exception):
23
    pass
24

25

26
class PyrexWarning(Exception):
27
    pass
28

29
class CannotSpecialize(PyrexError):
30
    pass
31

32
def context(position):
33
    source = position[0]
34
    assert not (isinstance(source, any_string_type)), (
35
        "Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source)
36
    try:
37
        F = source.get_lines()
38
    except UnicodeDecodeError:
39
        # file has an encoding problem
40
        s = "[unprintable code]\n"
41
    else:
42
        s = ''.join(F[max(0, position[1]-6):position[1]])
43
        s = '...\n%s%s^\n' % (s, ' '*(position[2]))
44
    s = '%s\n%s%s\n' % ('-'*60, s, '-'*60)
45
    return s
46

47
def format_position(position):
48
    if position:
49
        return "%s:%d:%d: " % (position[0].get_error_description(),
50
                                position[1], position[2])
51
    return ''
52

53
def format_error(message, position):
54
    if position:
55
        pos_str = format_position(position)
56
        cont = context(position)
57
        message = '\nError compiling Cython file:\n%s\n%s%s' % (cont, pos_str, message or '')
58
    return message
59

60
class CompileError(PyrexError):
61

62
    def __init__(self, position = None, message = ""):
63
        self.position = position
64
        self.message_only = message
65
        self.formatted_message = format_error(message, position)
66
        self.reported = False
67
        Exception.__init__(self, self.formatted_message)
68
        # Python Exception subclass pickling is broken,
69
        # see https://bugs.python.org/issue1692335
70
        self.args = (position, message)
71

72
    def __str__(self):
73
        return self.formatted_message
74

75
class CompileWarning(PyrexWarning):
76

77
    def __init__(self, position = None, message = ""):
78
        self.position = position
79
        Exception.__init__(self, format_position(position) + message)
80

81
class InternalError(Exception):
82
    # If this is ever raised, there is a bug in the compiler.
83

84
    def __init__(self, message):
85
        self.message_only = message
86
        Exception.__init__(self, "Internal compiler error: %s"
87
            % message)
88

89
class AbortError(Exception):
90
    # Throw this to stop the compilation immediately.
91

92
    def __init__(self, message):
93
        self.message_only = message
94
        Exception.__init__(self, "Abort error: %s" % message)
95

96
class CompilerCrash(CompileError):
97
    # raised when an unexpected exception occurs in a transform
98
    def __init__(self, pos, context, message, cause, stacktrace=None):
99
        if message:
100
            message = '\n' + message
101
        else:
102
            message = '\n'
103
        self.message_only = message
104
        if context:
105
            message = "Compiler crash in %s%s" % (context, message)
106
        if stacktrace:
107
            import traceback
108
            message += (
109
                '\n\nCompiler crash traceback from this point on:\n' +
110
                ''.join(traceback.format_tb(stacktrace)))
111
        if cause:
112
            if not stacktrace:
113
                message += '\n'
114
            message += '%s: %s' % (cause.__class__.__name__, cause)
115
        CompileError.__init__(self, pos, message)
116
        # Python Exception subclass pickling is broken,
117
        # see https://bugs.python.org/issue1692335
118
        self.args = (pos, context, message, cause, stacktrace)
119

120
class NoElementTreeInstalledException(PyrexError):
121
    """raised when the user enabled options.gdb_debug but no ElementTree
122
    implementation was found
123
    """
124

125
def open_listing_file(path, echo_to_stderr=True):
126
    # Begin a new error listing. If path is None, no file
127
    # is opened, the error counter is just reset.
128
    if path is not None:
129
        threadlocal.cython_errors_listing_file = open_new_file(path)
130
    else:
131
        threadlocal.cython_errors_listing_file = None
132
    if echo_to_stderr:
133
        threadlocal.cython_errors_echo_file = sys.stderr
134
    else:
135
        threadlocal.cython_errors_echo_file = None
136
    threadlocal.cython_errors_count = 0
137

138
def close_listing_file():
139
    if threadlocal.cython_errors_listing_file:
140
        threadlocal.cython_errors_listing_file.close()
141
        threadlocal.cython_errors_listing_file = None
142

143
def report_error(err, use_stack=True):
144
    error_stack = threadlocal.cython_errors_stack
145
    if error_stack and use_stack:
146
        error_stack[-1].append(err)
147
    else:
148
        # See Main.py for why dual reporting occurs. Quick fix for now.
149
        if err.reported: return
150
        err.reported = True
151
        try: line = "%s\n" % err
152
        except UnicodeEncodeError:
153
            # Python <= 2.5 does this for non-ASCII Unicode exceptions
154
            line = format_error(getattr(err, 'message_only', "[unprintable exception message]"),
155
                                getattr(err, 'position', None)) + '\n'
156
        listing_file = threadlocal.cython_errors_listing_file
157
        if listing_file:
158
            try: listing_file.write(line)
159
            except UnicodeEncodeError:
160
                listing_file.write(line.encode('ASCII', 'replace'))
161
        echo_file = threadlocal.cython_errors_echo_file
162
        if echo_file:
163
            try: echo_file.write(line)
164
            except UnicodeEncodeError:
165
                echo_file.write(line.encode('ASCII', 'replace'))
166
        threadlocal.cython_errors_count += 1
167
        if Options.fast_fail:
168
            raise AbortError("fatal errors")
169

170
def error(position, message):
171
    #print("Errors.error:", repr(position), repr(message)) ###
172
    if position is None:
173
        raise InternalError(message)
174
    err = CompileError(position, message)
175
    if DebugFlags.debug_exception_on_error: raise Exception(err)  # debug
176
    report_error(err)
177
    return err
178

179

180
LEVEL = 1  # warn about all errors level 1 or higher
181

182
def _write_file_encode(file, line):
183
    try:
184
        file.write(line)
185
    except UnicodeEncodeError:
186
        file.write(line.encode('ascii', 'replace'))
187

188

189
def performance_hint(position, message, env):
190
    if not env.directives['show_performance_hints']:
191
        return
192
    warn = CompileWarning(position, message)
193
    line = "performance hint: %s\n" % warn
194
    listing_file = threadlocal.cython_errors_listing_file
195
    if listing_file:
196
        _write_file_encode(listing_file, line)
197
    echo_file = threadlocal.cython_errors_echo_file
198
    if echo_file:
199
        _write_file_encode(echo_file, line)
200
    return warn
201

202

203
def message(position, message, level=1):
204
    if level < LEVEL:
205
        return
206
    warn = CompileWarning(position, message)
207
    line = "note: %s\n" % warn
208
    listing_file = threadlocal.cython_errors_listing_file
209
    if listing_file:
210
        _write_file_encode(listing_file, line)
211
    echo_file = threadlocal.cython_errors_echo_file
212
    if echo_file:
213
        _write_file_encode(echo_file, line)
214
    return warn
215

216

217
def warning(position, message, level=0):
218
    if level < LEVEL:
219
        return
220
    if Options.warning_errors and position:
221
        return error(position, message)
222
    warn = CompileWarning(position, message)
223
    line = "warning: %s\n" % warn
224
    listing_file = threadlocal.cython_errors_listing_file
225
    if listing_file:
226
        _write_file_encode(listing_file, line)
227
    echo_file = threadlocal.cython_errors_echo_file
228
    if echo_file:
229
        _write_file_encode(echo_file, line)
230
    return warn
231

232

233
def warn_once(position, message, level=0):
234
    if level < LEVEL:
235
        return
236
    warn_once_seen = threadlocal.cython_errors_warn_once_seen
237
    if message in warn_once_seen:
238
        return
239
    warn = CompileWarning(position, message)
240
    line = "warning: %s\n" % warn
241
    listing_file = threadlocal.cython_errors_listing_file
242
    if listing_file:
243
        _write_file_encode(listing_file, line)
244
    echo_file = threadlocal.cython_errors_echo_file
245
    if echo_file:
246
        _write_file_encode(echo_file, line)
247
    warn_once_seen.add(message)
248
    return warn
249

250

251
# These functions can be used to momentarily suppress errors.
252

253
def hold_errors():
254
    errors = []
255
    threadlocal.cython_errors_stack.append(errors)
256
    return errors
257

258

259
def release_errors(ignore=False):
260
    held_errors = threadlocal.cython_errors_stack.pop()
261
    if not ignore:
262
        for err in held_errors:
263
            report_error(err)
264

265

266
def held_errors():
267
    return threadlocal.cython_errors_stack[-1]
268

269

270
# same as context manager:
271

272
@contextmanager
273
def local_errors(ignore=False):
274
    errors = hold_errors()
275
    try:
276
        yield errors
277
    finally:
278
        release_errors(ignore=ignore)
279

280

281
# Keep all global state in thread local storage to support parallel cythonisation in distutils.
282

283
def init_thread():
284
    threadlocal.cython_errors_count = 0
285
    threadlocal.cython_errors_listing_file = None
286
    threadlocal.cython_errors_echo_file = None
287
    threadlocal.cython_errors_warn_once_seen = set()
288
    threadlocal.cython_errors_stack = []
289

290
def reset():
291
    threadlocal.cython_errors_warn_once_seen.clear()
292
    del threadlocal.cython_errors_stack[:]
293

294
def get_errors_count():
295
    return threadlocal.cython_errors_count
296

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.