Commit 613a4861 authored by Stefan Behnel's avatar Stefan Behnel

use PyErr_Format() instead of PyErr_SetString() for Cython generated...

use PyErr_Format() instead of PyErr_SetString() for Cython generated exceptions with formatted but constant messages
parent 450e56ea
...@@ -681,11 +681,11 @@ class ExprNode(Node): ...@@ -681,11 +681,11 @@ class ExprNode(Node):
def as_cython_attribute(self): def as_cython_attribute(self):
return None return None
def as_none_safe_node(self, message, error="PyExc_TypeError"): def as_none_safe_node(self, message, error="PyExc_TypeError", format_args=()):
# Wraps the node in a NoneCheckNode if it is not known to be # Wraps the node in a NoneCheckNode if it is not known to be
# not-None (e.g. because it is a Python literal). # not-None (e.g. because it is a Python literal).
if self.may_be_none(): if self.may_be_none():
return NoneCheckNode(self, error, message) return NoneCheckNode(self, error, message, format_args)
else: else:
return self return self
...@@ -3075,8 +3075,9 @@ class SimpleCallNode(CallNode): ...@@ -3075,8 +3075,9 @@ class SimpleCallNode(CallNode):
self_arg = func_type.args[0] self_arg = func_type.args[0]
if self_arg.not_none: # C methods must do the None test for self at *call* time if self_arg.not_none: # C methods must do the None test for self at *call* time
self.self = self.self.as_none_safe_node( self.self = self.self.as_none_safe_node(
"'NoneType' object has no attribute '%s'" % self.function.entry.name, "'NoneType' object has no attribute '%s'",
'PyExc_AttributeError') error = 'PyExc_AttributeError',
format_args = [self.function.entry.name])
expected_type = self_arg.type expected_type = self_arg.type
self.coerced_self = CloneNode(self.self).coerce_to( self.coerced_self = CloneNode(self.self).coerce_to(
expected_type, env) expected_type, env)
...@@ -7488,12 +7489,14 @@ class NoneCheckNode(CoercionNode): ...@@ -7488,12 +7489,14 @@ class NoneCheckNode(CoercionNode):
# raises an appropriate exception (as specified by the creating # raises an appropriate exception (as specified by the creating
# transform). # transform).
def __init__(self, arg, exception_type_cname, exception_message): def __init__(self, arg, exception_type_cname, exception_message,
exception_format_args):
CoercionNode.__init__(self, arg) CoercionNode.__init__(self, arg)
self.type = arg.type self.type = arg.type
self.result_ctype = arg.ctype() self.result_ctype = arg.ctype()
self.exception_type_cname = exception_type_cname self.exception_type_cname = exception_type_cname
self.exception_message = exception_message self.exception_message = exception_message
self.exception_format_args = tuple(exception_format_args or ())
def analyse_types(self, env): def analyse_types(self, env):
pass pass
...@@ -7513,11 +7516,20 @@ class NoneCheckNode(CoercionNode): ...@@ -7513,11 +7516,20 @@ class NoneCheckNode(CoercionNode):
def generate_result_code(self, code): def generate_result_code(self, code):
code.putln( code.putln(
"if (unlikely(%s == Py_None)) {" % self.arg.py_result()) "if (unlikely(%s == Py_None)) {" % self.arg.py_result())
code.putln('PyErr_SetString(%s, "%s"); %s ' % ( escape = StringEncoding.escape_byte_string
self.exception_type_cname, if self.exception_format_args:
StringEncoding.escape_byte_string( code.putln('PyErr_Format(%s, "%s", %s); %s ' % (
self.exception_message.encode('UTF-8')), self.exception_type_cname,
code.error_goto(self.pos))) StringEncoding.escape_byte_string(
self.exception_message.encode('UTF-8')),
', '.join([ '"%s"' % escape(str(arg).encode('UTF-8'))
for arg in self.exception_format_args ]),
code.error_goto(self.pos)))
else:
code.putln('PyErr_SetString(%s, "%s"); %s ' % (
self.exception_type_cname,
escape(self.exception_message.encode('UTF-8')),
code.error_goto(self.pos)))
code.putln("}") code.putln("}")
def generate_post_assignment_code(self, code): def generate_post_assignment_code(self, code):
......
...@@ -2789,12 +2789,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -2789,12 +2789,13 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
self_arg = args[0] self_arg = args[0]
if is_unbound_method: if is_unbound_method:
self_arg = self_arg.as_none_safe_node( self_arg = self_arg.as_none_safe_node(
"descriptor '%s' requires a '%s' object but received a 'NoneType'" % ( "descriptor '%s' requires a '%s' object but received a 'NoneType'",
attr_name, node.function.obj.name)) format_args = [attr_name, node.function.obj.name])
else: else:
self_arg = self_arg.as_none_safe_node( self_arg = self_arg.as_none_safe_node(
"'NoneType' object has no attribute '%s'" % attr_name, "'NoneType' object has no attribute '%s'",
error = "PyExc_AttributeError") error = "PyExc_AttributeError",
format_args = [attr_name])
args[0] = self_arg args[0] = self_arg
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, name, func_type, node.pos, name, func_type,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment