|
|
|
|
|
|
|
|
| from __future__ import absolute_import
|
|
|
| try:
|
| from __builtin__ import basestring as any_string_type
|
| except ImportError:
|
| any_string_type = (bytes, str)
|
|
|
| import sys
|
| from contextlib import contextmanager
|
|
|
| try:
|
| from threading import local as _threadlocal
|
| except ImportError:
|
| class _threadlocal(object): 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 = u"[unprintable code]\n"
|
| else:
|
| s = u''.join(F[max(0, position[1]-6):position[1]])
|
| s = u'...\n%s%s^\n' % (s, u' '*(position[2]))
|
| s = u'%s\n%s%s\n' % (u'-'*60, s, u'-'*60)
|
| return s
|
|
|
| def format_position(position):
|
| if position:
|
| return u"%s:%d:%d: " % (position[0].get_error_description(),
|
| position[1], position[2])
|
| return u''
|
|
|
| def format_error(message, position):
|
| if position:
|
| pos_str = format_position(position)
|
| cont = context(position)
|
| message = u'\nError compiling Cython file:\n%s\n%s%s' % (cont, pos_str, message or u'')
|
| return message
|
|
|
| class CompileError(PyrexError):
|
|
|
| def __init__(self, position = None, message = u""):
|
| 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, u"Internal compiler error: %s"
|
| % message)
|
|
|
| class AbortError(Exception):
|
|
|
|
|
| def __init__(self, message):
|
| self.message_only = message
|
| Exception.__init__(self, u"Abort error: %s" % message)
|
|
|
| class CompilerCrash(CompileError):
|
|
|
| def __init__(self, pos, context, message, cause, stacktrace=None):
|
| if message:
|
| message = u'\n' + message
|
| else:
|
| message = u'\n'
|
| self.message_only = message
|
| if context:
|
| message = u"Compiler crash in %s%s" % (context, message)
|
| if stacktrace:
|
| import traceback
|
| message += (
|
| u'\n\nCompiler crash traceback from this point on:\n' +
|
| u''.join(traceback.format_tb(stacktrace)))
|
| if cause:
|
| if not stacktrace:
|
| message += u'\n'
|
| message += u'%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 = u"%s\n" % err
|
| except UnicodeEncodeError:
|
|
|
| line = format_error(getattr(err, 'message_only', "[unprintable exception message]"),
|
| getattr(err, 'position', None)) + u'\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 = u"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 = u"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 = u"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
|
|
|