| |
| |
| |
|
|
| any_string_type = (bytes, str) |
|
|
| import sys |
| from contextlib import contextmanager |
|
|
| try: |
| from threading import local as _threadlocal |
| except ImportError: |
| class _threadlocal: pass |
|
|
| threadlocal = _threadlocal() |
|
|
| from ..Utils import open_new_file |
| from . import DebugFlags |
| from . import Options |
|
|
|
|
| class PyrexError(Exception): |
| pass |
|
|
|
|
| class PyrexWarning(Exception): |
| pass |
|
|
| class CannotSpecialize(PyrexError): |
| pass |
|
|
| def context(position): |
| source = position[0] |
| assert not (isinstance(source, any_string_type)), ( |
| "Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source) |
| try: |
| F = source.get_lines() |
| except UnicodeDecodeError: |
| |
| s = "[unprintable code]\n" |
| else: |
| s = ''.join(F[max(0, position[1]-6):position[1]]) |
| s = '...\n%s%s^\n' % (s, ' '*(position[2])) |
| s = '%s\n%s%s\n' % ('-'*60, s, '-'*60) |
| return s |
|
|
| def format_position(position): |
| if position: |
| return "%s:%d:%d: " % (position[0].get_error_description(), |
| position[1], position[2]) |
| return '' |
|
|
| def format_error(message, position): |
| if position: |
| pos_str = format_position(position) |
| cont = context(position) |
| message = '\nError compiling Cython file:\n%s\n%s%s' % (cont, pos_str, message or '') |
| return message |
|
|
| class CompileError(PyrexError): |
|
|
| def __init__(self, position = None, message = ""): |
| self.position = position |
| self.message_only = message |
| self.formatted_message = format_error(message, position) |
| self.reported = False |
| Exception.__init__(self, self.formatted_message) |
| |
| |
| self.args = (position, message) |
|
|
| def __str__(self): |
| return self.formatted_message |
|
|
| class CompileWarning(PyrexWarning): |
|
|
| def __init__(self, position = None, message = ""): |
| self.position = position |
| Exception.__init__(self, format_position(position) + message) |
|
|
| class InternalError(Exception): |
| |
|
|
| def __init__(self, message): |
| self.message_only = message |
| Exception.__init__(self, "Internal compiler error: %s" |
| % message) |
|
|
| class AbortError(Exception): |
| |
|
|
| def __init__(self, message): |
| self.message_only = message |
| Exception.__init__(self, "Abort error: %s" % message) |
|
|
| class CompilerCrash(CompileError): |
| |
| def __init__(self, pos, context, message, cause, stacktrace=None): |
| if message: |
| message = '\n' + message |
| else: |
| message = '\n' |
| self.message_only = message |
| if context: |
| message = "Compiler crash in %s%s" % (context, message) |
| if stacktrace: |
| import traceback |
| message += ( |
| '\n\nCompiler crash traceback from this point on:\n' + |
| ''.join(traceback.format_tb(stacktrace))) |
| if cause: |
| if not stacktrace: |
| message += '\n' |
| message += '%s: %s' % (cause.__class__.__name__, cause) |
| CompileError.__init__(self, pos, message) |
| |
| |
| self.args = (pos, context, message, cause, stacktrace) |
|
|
| class NoElementTreeInstalledException(PyrexError): |
| """raised when the user enabled options.gdb_debug but no ElementTree |
| implementation was found |
| """ |
|
|
| def open_listing_file(path, echo_to_stderr=True): |
| |
| |
| if path is not None: |
| threadlocal.cython_errors_listing_file = open_new_file(path) |
| else: |
| threadlocal.cython_errors_listing_file = None |
| if echo_to_stderr: |
| threadlocal.cython_errors_echo_file = sys.stderr |
| else: |
| threadlocal.cython_errors_echo_file = None |
| threadlocal.cython_errors_count = 0 |
|
|
| def close_listing_file(): |
| if threadlocal.cython_errors_listing_file: |
| threadlocal.cython_errors_listing_file.close() |
| threadlocal.cython_errors_listing_file = None |
|
|
| def report_error(err, use_stack=True): |
| error_stack = threadlocal.cython_errors_stack |
| if error_stack and use_stack: |
| error_stack[-1].append(err) |
| else: |
| |
| if err.reported: return |
| err.reported = True |
| try: line = "%s\n" % err |
| except UnicodeEncodeError: |
| |
| line = format_error(getattr(err, 'message_only', "[unprintable exception message]"), |
| getattr(err, 'position', None)) + '\n' |
| listing_file = threadlocal.cython_errors_listing_file |
| if listing_file: |
| try: listing_file.write(line) |
| except UnicodeEncodeError: |
| listing_file.write(line.encode('ASCII', 'replace')) |
| echo_file = threadlocal.cython_errors_echo_file |
| if echo_file: |
| try: echo_file.write(line) |
| except UnicodeEncodeError: |
| echo_file.write(line.encode('ASCII', 'replace')) |
| threadlocal.cython_errors_count += 1 |
| if Options.fast_fail: |
| raise AbortError("fatal errors") |
|
|
| def error(position, message): |
| |
| if position is None: |
| raise InternalError(message) |
| err = CompileError(position, message) |
| if DebugFlags.debug_exception_on_error: raise Exception(err) |
| report_error(err) |
| return err |
|
|
|
|
| LEVEL = 1 |
|
|
| def _write_file_encode(file, line): |
| try: |
| file.write(line) |
| except UnicodeEncodeError: |
| file.write(line.encode('ascii', 'replace')) |
|
|
|
|
| def performance_hint(position, message, env): |
| if not env.directives['show_performance_hints']: |
| return |
| warn = CompileWarning(position, message) |
| line = "performance hint: %s\n" % warn |
| listing_file = threadlocal.cython_errors_listing_file |
| if listing_file: |
| _write_file_encode(listing_file, line) |
| echo_file = threadlocal.cython_errors_echo_file |
| if echo_file: |
| _write_file_encode(echo_file, line) |
| return warn |
|
|
|
|
| def message(position, message, level=1): |
| if level < LEVEL: |
| return |
| warn = CompileWarning(position, message) |
| line = "note: %s\n" % warn |
| listing_file = threadlocal.cython_errors_listing_file |
| if listing_file: |
| _write_file_encode(listing_file, line) |
| echo_file = threadlocal.cython_errors_echo_file |
| if echo_file: |
| _write_file_encode(echo_file, line) |
| return warn |
|
|
|
|
| def warning(position, message, level=0): |
| if level < LEVEL: |
| return |
| if Options.warning_errors and position: |
| return error(position, message) |
| warn = CompileWarning(position, message) |
| line = "warning: %s\n" % warn |
| listing_file = threadlocal.cython_errors_listing_file |
| if listing_file: |
| _write_file_encode(listing_file, line) |
| echo_file = threadlocal.cython_errors_echo_file |
| if echo_file: |
| _write_file_encode(echo_file, line) |
| return warn |
|
|
|
|
| def warn_once(position, message, level=0): |
| if level < LEVEL: |
| return |
| warn_once_seen = threadlocal.cython_errors_warn_once_seen |
| if message in warn_once_seen: |
| return |
| warn = CompileWarning(position, message) |
| line = "warning: %s\n" % warn |
| listing_file = threadlocal.cython_errors_listing_file |
| if listing_file: |
| _write_file_encode(listing_file, line) |
| echo_file = threadlocal.cython_errors_echo_file |
| if echo_file: |
| _write_file_encode(echo_file, line) |
| warn_once_seen.add(message) |
| return warn |
|
|
|
|
| |
|
|
| def hold_errors(): |
| errors = [] |
| threadlocal.cython_errors_stack.append(errors) |
| return errors |
|
|
|
|
| def release_errors(ignore=False): |
| held_errors = threadlocal.cython_errors_stack.pop() |
| if not ignore: |
| for err in held_errors: |
| report_error(err) |
|
|
|
|
| def held_errors(): |
| return threadlocal.cython_errors_stack[-1] |
|
|
|
|
| |
|
|
| @contextmanager |
| def local_errors(ignore=False): |
| errors = hold_errors() |
| try: |
| yield errors |
| finally: |
| release_errors(ignore=ignore) |
|
|
|
|
| |
|
|
| def init_thread(): |
| threadlocal.cython_errors_count = 0 |
| threadlocal.cython_errors_listing_file = None |
| threadlocal.cython_errors_echo_file = None |
| threadlocal.cython_errors_warn_once_seen = set() |
| threadlocal.cython_errors_stack = [] |
|
|
| def reset(): |
| threadlocal.cython_errors_warn_once_seen.clear() |
| del threadlocal.cython_errors_stack[:] |
|
|
| def get_errors_count(): |
| return threadlocal.cython_errors_count |
|
|