Commit cf61552b authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Merge

parents bbba7ca8 364dfc77
from Cython.Compiler.Visitor import TreeVisitor, get_temp_name_handle_desc from Cython.Compiler.Visitor import TreeVisitor
from Cython.Compiler.Nodes import * from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import * from Cython.Compiler.ExprNodes import *
...@@ -37,6 +37,7 @@ class CodeWriter(TreeVisitor): ...@@ -37,6 +37,7 @@ class CodeWriter(TreeVisitor):
self.result = result self.result = result
self.numindents = 0 self.numindents = 0
self.tempnames = {} self.tempnames = {}
self.tempblockindex = 0
def write(self, tree): def write(self, tree):
self.visit(tree) self.visit(tree)
...@@ -60,12 +61,6 @@ class CodeWriter(TreeVisitor): ...@@ -60,12 +61,6 @@ class CodeWriter(TreeVisitor):
self.startline(s) self.startline(s)
self.endline() self.endline()
def putname(self, name):
tmpdesc = get_temp_name_handle_desc(name)
if tmpdesc is not None:
name = self.tempnames.setdefault(tmpdesc, u"$" +tmpdesc)
self.put(name)
def comma_seperated_list(self, items, output_rhs=False): def comma_seperated_list(self, items, output_rhs=False):
if len(items) > 0: if len(items) > 0:
for item in items[:-1]: for item in items[:-1]:
...@@ -132,7 +127,7 @@ class CodeWriter(TreeVisitor): ...@@ -132,7 +127,7 @@ class CodeWriter(TreeVisitor):
self.endline() self.endline()
def visit_NameNode(self, node): def visit_NameNode(self, node):
self.putname(node.name) self.put(node.name)
def visit_IntNode(self, node): def visit_IntNode(self, node):
self.put(node.value) self.put(node.value)
...@@ -312,3 +307,18 @@ class CodeWriter(TreeVisitor): ...@@ -312,3 +307,18 @@ class CodeWriter(TreeVisitor):
self.visit(node.operand) self.visit(node.operand)
self.put(u")") self.put(u")")
def visit_TempsBlockNode(self, node):
"""
Temporaries are output like $1_1', where the first number is
an index of the TempsBlockNode and the second number is an index
of the temporary which that block allocates.
"""
idx = 0
for handle in node.temps:
self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
idx += 1
self.tempblockindex += 1
self.visit(node.body)
def visit_TempRefNode(self, node):
self.put(self.tempnames[node.handle])
from Cython.Compiler.Visitor import VisitorTransform, temp_name_handle, CythonTransform from Cython.Compiler.Visitor import VisitorTransform, CythonTransform
from Cython.Compiler.ModuleNode import ModuleNode from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import * from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import * from Cython.Compiler.ExprNodes import *
from Cython.Compiler.TreeFragment import TreeFragment
from Cython.Compiler.StringEncoding import EncodedString from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler.Errors import CompileError from Cython.Compiler.Errors import CompileError
import Interpreter import Interpreter
......
from Cython.Compiler.Visitor import VisitorTransform, temp_name_handle, CythonTransform from Cython.Compiler.Visitor import VisitorTransform, CythonTransform
from Cython.Compiler.ModuleNode import ModuleNode from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import * from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import * from Cython.Compiler.ExprNodes import *
......
...@@ -168,6 +168,7 @@ class ExprNode(Node): ...@@ -168,6 +168,7 @@ class ExprNode(Node):
saved_subexpr_nodes = None saved_subexpr_nodes = None
is_temp = 0 is_temp = 0
is_target = 0
def get_child_attrs(self): def get_child_attrs(self):
return self.subexprs return self.subexprs
...@@ -206,10 +207,10 @@ class ExprNode(Node): ...@@ -206,10 +207,10 @@ class ExprNode(Node):
return self.saved_subexpr_nodes return self.saved_subexpr_nodes
def result(self): def result(self):
if self.is_temp: if not self.is_temp or self.is_target:
return self.result_code
else:
return self.calculate_result_code() return self.calculate_result_code()
else: # i.e. self.is_temp:
return self.result_code
def result_as(self, type = None): def result_as(self, type = None):
# Return the result code cast to the specified C type. # Return the result code cast to the specified C type.
...@@ -335,7 +336,7 @@ class ExprNode(Node): ...@@ -335,7 +336,7 @@ class ExprNode(Node):
if debug_temp_alloc: if debug_temp_alloc:
print("%s Allocating target temps" % self) print("%s Allocating target temps" % self)
self.allocate_subexpr_temps(env) self.allocate_subexpr_temps(env)
self.result_code = self.target_code() self.is_target = True
if rhs: if rhs:
rhs.release_temp(env) rhs.release_temp(env)
self.release_subexpr_temps(env) self.release_subexpr_temps(env)
...@@ -560,6 +561,66 @@ class ExprNode(Node): ...@@ -560,6 +561,66 @@ class ExprNode(Node):
return self.result_in_temp() return self.result_in_temp()
class NewTempExprNode(ExprNode):
backwards_compatible_result = None
def result(self):
if self.is_temp:
return self.temp_code
else:
return self.calculate_result_code()
def allocate_target_temps(self, env, rhs):
self.allocate_subexpr_temps(env)
rhs.release_temp(rhs)
self.releasesubexpr_temps(env)
def allocate_temps(self, env, result = None):
self.allocate_subexpr_temps(env)
self.backwards_compatible_result = result
if self.is_temp:
self.release_subexpr_temps(env)
def allocate_temp(self, env, result = None):
assert result is None
def release_temp(self, env):
pass
def generate_result_code(self, code):
if self.is_temp:
type = self.type
if not type.is_void:
if type.is_pyobject:
type = PyrexTypes.py_object_type
if self.backwards_compatible_result:
self.temp_code = self.backwards_compatible_result
else:
self.temp_code = code.funcstate.allocate_temp(type)
else:
self.temp_code = None
def generate_disposal_code(self, code):
if self.is_temp:
if self.type.is_pyobject:
code.put_decref_clear(self.result(), self.ctype())
if not self.backwards_compatible_result:
code.funcstate.release_temp(self.temp_code)
else:
self.generate_subexpr_disposal_code(code)
def generate_post_assignment_code(self, code):
if self.is_temp:
if self.type.is_pyobject:
code.putln("%s = 0;" % self.temp_code)
if not self.backwards_compatible_result:
code.funcstate.release_temp(self.temp_code)
else:
self.generate_subexpr_disposal_code(code)
class AtomicExprNode(ExprNode): class AtomicExprNode(ExprNode):
# Abstract base class for expression nodes which have # Abstract base class for expression nodes which have
# no sub-expressions. # no sub-expressions.
...@@ -1499,7 +1560,8 @@ class IndexNode(ExprNode): ...@@ -1499,7 +1560,8 @@ class IndexNode(ExprNode):
def generate_result_code(self, code): def generate_result_code(self, code):
if self.is_buffer_access: if self.is_buffer_access:
# buffer_pointer_code is returned by result() if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
ptrcode = self.buffer_lookup_code(code) ptrcode = self.buffer_lookup_code(code)
code.putln("%s = *%s;" % ( code.putln("%s = *%s;" % (
self.result(), self.result(),
...@@ -1543,6 +1605,8 @@ class IndexNode(ExprNode): ...@@ -1543,6 +1605,8 @@ class IndexNode(ExprNode):
def generate_buffer_setitem_code(self, rhs, code, op=""): def generate_buffer_setitem_code(self, rhs, code, op=""):
# Used from generate_assignment_code and InPlaceAssignmentNode # Used from generate_assignment_code and InPlaceAssignmentNode
if code.globalstate.directives['nonecheck']:
self.put_nonecheck(code)
ptrexpr = self.buffer_lookup_code(code) ptrexpr = self.buffer_lookup_code(code)
if self.buffer_type.dtype.is_pyobject: if self.buffer_type.dtype.is_pyobject:
# Must manage refcounts. Decref what is already there # Must manage refcounts. Decref what is already there
...@@ -1609,6 +1673,13 @@ class IndexNode(ExprNode): ...@@ -1609,6 +1673,13 @@ class IndexNode(ExprNode):
options=code.globalstate.directives, options=code.globalstate.directives,
pos=self.pos, code=code) pos=self.pos, code=code)
def put_nonecheck(self, code):
code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
code.putln("if (%s) {" % code.unlikely("%s == Py_None") % self.base.result_as(PyrexTypes.py_object_type))
code.putln("__Pyx_RaiseNoneIndexingError();")
code.putln(code.error_goto(self.pos))
code.putln("}")
class SliceIndexNode(ExprNode): class SliceIndexNode(ExprNode):
# 2-element slice indexing # 2-element slice indexing
# #
...@@ -3211,7 +3282,7 @@ def get_compile_time_binop(node): ...@@ -3211,7 +3282,7 @@ def get_compile_time_binop(node):
% node.operator) % node.operator)
return func return func
class BinopNode(ExprNode): class BinopNode(NewTempExprNode):
# operator string # operator string
# operand1 ExprNode # operand1 ExprNode
# operand2 ExprNode # operand2 ExprNode
...@@ -3261,6 +3332,7 @@ class BinopNode(ExprNode): ...@@ -3261,6 +3332,7 @@ class BinopNode(ExprNode):
self.operand2.check_const() self.operand2.check_const()
def generate_result_code(self, code): def generate_result_code(self, code):
NewTempExprNode.generate_result_code(self, code)
#print "BinopNode.generate_result_code:", self.operand1, self.operand2 ### #print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
if self.operand1.type.is_pyobject: if self.operand1.type.is_pyobject:
function = self.py_operation_function() function = self.py_operation_function()
...@@ -4589,3 +4661,12 @@ static INLINE void __Pyx_RaiseNoneAttributeError(char* attrname) { ...@@ -4589,3 +4661,12 @@ static INLINE void __Pyx_RaiseNoneAttributeError(char* attrname) {
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname); PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", attrname);
} }
"""] """]
raise_noneindex_error_utility_code = [
"""
static INLINE void __Pyx_RaiseNoneIndexingError();
""", """
static INLINE void __Pyx_RaiseNoneIndexingError() {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is unsubscriptable");
}
"""]
...@@ -4188,6 +4188,7 @@ class FromImportStatNode(StatNode): ...@@ -4188,6 +4188,7 @@ class FromImportStatNode(StatNode):
self.module.generate_disposal_code(code) self.module.generate_disposal_code(code)
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# Runtime support code # Runtime support code
......
from Cython.Compiler.Visitor import VisitorTransform, temp_name_handle, CythonTransform from Cython.Compiler.Visitor import VisitorTransform, CythonTransform
from Cython.Compiler.ModuleNode import ModuleNode from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import * from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import * from Cython.Compiler.ExprNodes import *
from Cython.Compiler.UtilNodes import *
from Cython.Compiler.TreeFragment import TreeFragment from Cython.Compiler.TreeFragment import TreeFragment
from Cython.Compiler.StringEncoding import EncodedString from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler.Errors import CompileError from Cython.Compiler.Errors import CompileError
...@@ -409,7 +410,7 @@ class WithTransform(CythonTransform): ...@@ -409,7 +410,7 @@ class WithTransform(CythonTransform):
finally: finally:
if EXC: if EXC:
EXIT(None, None, None) EXIT(None, None, None)
""", temps=[u'MGR', u'EXC', u"EXIT", u"SYS)"], """, temps=[u'MGR', u'EXC', u"EXIT"],
pipeline=[NormalizeTree(None)]) pipeline=[NormalizeTree(None)])
template_with_target = TreeFragment(u""" template_with_target = TreeFragment(u"""
...@@ -428,32 +429,32 @@ class WithTransform(CythonTransform): ...@@ -428,32 +429,32 @@ class WithTransform(CythonTransform):
finally: finally:
if EXC: if EXC:
EXIT(None, None, None) EXIT(None, None, None)
""", temps=[u'MGR', u'EXC', u"EXIT", u"VALUE", u"SYS"], """, temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
pipeline=[NormalizeTree(None)]) pipeline=[NormalizeTree(None)])
def visit_WithStatNode(self, node): def visit_WithStatNode(self, node):
excinfo_name = temp_name_handle('EXCINFO') excinfo_temp = TempHandle(PyrexTypes.py_object_type)
excinfo_namenode = NameNode(pos=node.pos, name=excinfo_name)
excinfo_target = NameNode(pos=node.pos, name=excinfo_name)
if node.target is not None: if node.target is not None:
result = self.template_with_target.substitute({ result = self.template_with_target.substitute({
u'EXPR' : node.manager, u'EXPR' : node.manager,
u'BODY' : node.body, u'BODY' : node.body,
u'TARGET' : node.target, u'TARGET' : node.target,
u'EXCINFO' : excinfo_namenode u'EXCINFO' : excinfo_temp.ref(node.pos)
}, pos=node.pos) }, pos=node.pos)
# Set except excinfo target to EXCINFO # Set except excinfo target to EXCINFO
result.stats[4].body.stats[0].except_clauses[0].excinfo_target = excinfo_target result.body.stats[4].body.stats[0].except_clauses[0].excinfo_target = (
excinfo_temp.ref(node.pos))
else: else:
result = self.template_without_target.substitute({ result = self.template_without_target.substitute({
u'EXPR' : node.manager, u'EXPR' : node.manager,
u'BODY' : node.body, u'BODY' : node.body,
u'EXCINFO' : excinfo_namenode u'EXCINFO' : excinfo_temp.ref(node.pos)
}, pos=node.pos) }, pos=node.pos)
# Set except excinfo target to EXCINFO # Set except excinfo target to EXCINFO
result.stats[4].body.stats[0].except_clauses[0].excinfo_target = excinfo_target result.body.stats[4].body.stats[0].except_clauses[0].excinfo_target = (
excinfo_temp.ref(node.pos))
return result.stats return TempsBlockNode(node.pos, temps=[excinfo_temp], body=result)
class DecoratorTransform(CythonTransform): class DecoratorTransform(CythonTransform):
......
...@@ -95,20 +95,20 @@ class TestWithTransform(TransformTest): ...@@ -95,20 +95,20 @@ class TestWithTransform(TransformTest):
self.assertCode(u""" self.assertCode(u"""
$MGR = x $1_0 = x
$EXIT = $MGR.__exit__ $1_2 = $1_0.__exit__
$MGR.__enter__() $1_0.__enter__()
$EXC = True $1_1 = True
try: try:
try: try:
y = z ** 3 y = z ** 3
except: except:
$EXC = False $1_1 = False
if (not $EXIT($EXCINFO)): if (not $1_2($0_0)):
raise raise
finally: finally:
if $EXC: if $1_1:
$EXIT(None, None, None) $1_2(None, None, None)
""", t) """, t)
...@@ -119,21 +119,21 @@ class TestWithTransform(TransformTest): ...@@ -119,21 +119,21 @@ class TestWithTransform(TransformTest):
""") """)
self.assertCode(u""" self.assertCode(u"""
$MGR = x $1_0 = x
$EXIT = $MGR.__exit__ $1_2 = $1_0.__exit__
$VALUE = $MGR.__enter__() $1_3 = $1_0.__enter__()
$EXC = True $1_1 = True
try: try:
try: try:
y = $VALUE y = $1_3
y = z ** 3 y = z ** 3
except: except:
$EXC = False $1_1 = False
if (not $EXIT($EXCINFO)): if (not $1_2($0_0)):
raise raise
finally: finally:
if $EXC: if $1_1:
$EXIT(None, None, None) $1_2(None, None, None)
""", t) """, t)
......
from Cython.TestUtils import CythonTest from Cython.TestUtils import CythonTest
from Cython.Compiler.TreeFragment import * from Cython.Compiler.TreeFragment import *
from Cython.Compiler.Nodes import * from Cython.Compiler.Nodes import *
from Cython.Compiler.UtilNodes import *
import Cython.Compiler.Naming as Naming import Cython.Compiler.Naming as Naming
class TestTreeFragments(CythonTest): class TestTreeFragments(CythonTest):
...@@ -54,10 +55,10 @@ class TestTreeFragments(CythonTest): ...@@ -54,10 +55,10 @@ class TestTreeFragments(CythonTest):
x = TMP x = TMP
""") """)
T = F.substitute(temps=[u"TMP"]) T = F.substitute(temps=[u"TMP"])
s = T.stats s = T.body.stats
self.assert_(s[0].expr.name == Naming.temp_prefix + u"1_TMP", s[0].expr.name) self.assert_(isinstance(s[0].expr, TempRefNode))
self.assert_(s[1].rhs.name == Naming.temp_prefix + u"1_TMP") self.assert_(isinstance(s[1].rhs, TempRefNode))
self.assert_(s[0].expr.name != u"TMP") self.assert_(s[0].expr.handle is s[1].rhs.handle)
if __name__ == "__main__": if __name__ == "__main__":
import unittest import unittest
......
...@@ -8,11 +8,12 @@ from Scanning import PyrexScanner, StringSourceDescriptor ...@@ -8,11 +8,12 @@ from Scanning import PyrexScanner, StringSourceDescriptor
from Symtab import BuiltinScope, ModuleScope from Symtab import BuiltinScope, ModuleScope
import Symtab import Symtab
import PyrexTypes import PyrexTypes
from Visitor import VisitorTransform, temp_name_handle from Visitor import VisitorTransform
from Nodes import Node, StatListNode from Nodes import Node, StatListNode
from ExprNodes import NameNode from ExprNodes import NameNode
import Parsing import Parsing
import Main import Main
import UtilNodes
""" """
Support for parsing strings into code trees. Support for parsing strings into code trees.
...@@ -111,12 +112,20 @@ class TemplateTransform(VisitorTransform): ...@@ -111,12 +112,20 @@ class TemplateTransform(VisitorTransform):
def __call__(self, node, substitutions, temps, pos): def __call__(self, node, substitutions, temps, pos):
self.substitutions = substitutions self.substitutions = substitutions
tempdict = {}
for key in temps:
tempdict[key] = temp_name_handle(key) # pending result_code refactor: Symtab.new_temp(PyrexTypes.py_object_type, key)
self.temp_key_to_entries = tempdict
self.pos = pos self.pos = pos
return super(TemplateTransform, self).__call__(node) tempmap = {}
temphandles = []
for temp in temps:
handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
tempmap[temp] = handle
temphandles.append(handle)
self.tempmap = tempmap
result = super(TemplateTransform, self).__call__(node)
if temps:
result = UtilNodes.TempsBlockNode(self.get_pos(node),
temps=temphandles,
body=result)
return result
def get_pos(self, node): def get_pos(self, node):
if self.pos: if self.pos:
...@@ -143,13 +152,11 @@ class TemplateTransform(VisitorTransform): ...@@ -143,13 +152,11 @@ class TemplateTransform(VisitorTransform):
else: else:
return self.visit_Node(node) # make copy as usual return self.visit_Node(node) # make copy as usual
def visit_NameNode(self, node): def visit_NameNode(self, node):
tempentry = self.temp_key_to_entries.get(node.name) temphandle = self.tempmap.get(node.name)
if tempentry is not None: if temphandle:
# Replace name with temporary # Replace name with temporary
return NameNode(self.get_pos(node), name=tempentry) return temphandle.ref(self.get_pos(node))
# Pending result_code refactor: return NameNode(self.get_pos(node), entry=tempentry)
else: else:
return self.try_substitution(node, node.name) return self.try_substitution(node, node.name)
......
#
# Nodes used as utilities and support for transforms etc.
# These often make up sets including both Nodes and ExprNodes
# so it is convenient to have them in a seperate module.
#
import Nodes
import ExprNodes
from Nodes import Node
from ExprNodes import ExprNode
class TempHandle(object):
temp = None
def __init__(self, type):
self.type = type
def ref(self, pos):
return TempRefNode(pos, handle=self, type=self.type)
class TempRefNode(ExprNode):
# handle TempHandle
subexprs = []
def analyse_types(self, env):
assert self.type == self.handle.type
def analyse_target_types(self, env):
assert self.type == self.handle.type
def analyse_target_declaration(self, env):
pass
def calculate_result_code(self):
result = self.handle.temp
if result is None: result = "<error>" # might be called and overwritten
return result
def generate_result_code(self, code):
pass
def generate_assignment_code(self, rhs, code):
if self.type.is_pyobject:
rhs.make_owned_reference(code)
code.put_xdecref(self.result(), self.ctype())
code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
rhs.generate_post_assignment_code(code)
class TempsBlockNode(Node):
"""
Creates a block which allocates temporary variables.
This is used by transforms to output constructs that need
to make use of a temporary variable. Simply pass the types
of the needed temporaries to the constructor.
The variables can be referred to using a TempRefNode
(which can be constructed by calling get_ref_node).
"""
# temps [TempHandle]
# body StatNode
child_attrs = ["body"]
def generate_execution_code(self, code):
for handle in self.temps:
handle.temp = code.funcstate.allocate_temp(handle.type)
self.body.generate_execution_code(code)
for handle in self.temps:
code.funcstate.release_temp(handle.temp)
def analyse_control_flow(self, env):
self.body.analyse_control_flow(env)
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
def generate_function_definitions(self, env, code):
self.body.generate_function_definitions(env, code)
def annotate(self, code):
self.body.annotate(code)
...@@ -199,23 +199,6 @@ def replace_node(ptr, value): ...@@ -199,23 +199,6 @@ def replace_node(ptr, value):
else: else:
getattr(parent, attrname)[listidx] = value getattr(parent, attrname)[listidx] = value
tmpnamectr = 0
def temp_name_handle(description=None):
global tmpnamectr
tmpnamectr += 1
if description is not None:
name = u"%d_%s" % (tmpnamectr, description)
else:
name = u"%d" % tmpnamectr
return EncodedString(Naming.temp_prefix + name)
def get_temp_name_handle_desc(handle):
if not handle.startswith(u"__cyt_"):
return None
else:
idx = handle.find(u"_", 6)
return handle[idx+1:]
class PrintTree(TreeVisitor): class PrintTree(TreeVisitor):
"""Prints a representation of the tree to standard output. """Prints a representation of the tree to standard output.
Subclass and override repr_of to provide more information Subclass and override repr_of to provide more information
......
...@@ -47,10 +47,16 @@ class CythonTest(unittest.TestCase): ...@@ -47,10 +47,16 @@ class CythonTest(unittest.TestCase):
self.assertEqual(len(expected), len(result), self.assertEqual(len(expected), len(result),
"Unmatched lines. Got:\n%s\nExpected:\n%s" % ("\n".join(expected), u"\n".join(result))) "Unmatched lines. Got:\n%s\nExpected:\n%s" % ("\n".join(expected), u"\n".join(result)))
def assertCode(self, expected, result_tree): def codeToLines(self, tree):
writer = CodeWriter() writer = CodeWriter()
writer.write(result_tree) writer.write(tree)
result_lines = writer.result.lines return writer.result.lines
def codeToString(self, tree):
return "\n".join(self.codeToLines(tree))
def assertCode(self, expected, result_tree):
result_lines = self.codeToLines(result_tree)
expected_lines = strip_common_indent(expected.split("\n")) expected_lines = strip_common_indent(expected.split("\n"))
......
...@@ -32,6 +32,16 @@ Traceback (most recent call last): ...@@ -32,6 +32,16 @@ Traceback (most recent call last):
... ...
AttributeError: 'NoneType' object has no attribute 'a' AttributeError: 'NoneType' object has no attribute 'a'
>>> check_buffer_get(None)
Traceback (most recent call last):
...
TypeError: 'NoneType' object is unsubscriptable
>>> check_buffer_set(None)
Traceback (most recent call last):
...
TypeError: 'NoneType' object is unsubscriptable
""" """
cimport cython cimport cython
...@@ -70,3 +80,11 @@ def check_and_assign(MyClass var): ...@@ -70,3 +80,11 @@ def check_and_assign(MyClass var):
var = None var = None
print var.a print var.a
@cython.nonecheck(True)
def check_buffer_get(object[int] buf):
return buf[0]
@cython.nonecheck(True)
def check_buffer_set(object[int] buf):
buf[0] = 1
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