Commit cc9f1333 authored by Stefan Behnel's avatar Stefan Behnel

support 'not None' and 'or None' on any Python argument

parent 12ad333d
......@@ -1405,6 +1405,7 @@ class FuncDefNode(StatNode, BlockNode):
def generate_arg_type_test(self, arg, code):
# Generate type test for one argument.
if arg.type.typeobj_is_available():
code.globalstate.use_utility_code(arg_type_test_utility_code)
typeptr_cname = arg.type.typeptr_cname
arg_code = "((PyObject *)%s)" % arg.entry.cname
code.putln(
......@@ -1419,6 +1420,15 @@ class FuncDefNode(StatNode, BlockNode):
error(arg.pos, "Cannot test type of extern C class "
"without type object name specification")
def generate_arg_none_check(self, arg, code):
# Generate None check for one argument.
code.globalstate.use_utility_code(arg_type_test_utility_code)
code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % arg.entry.cname)
code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % (
arg.name,
code.error_goto(arg.pos)))
code.putln('}')
def generate_wrapper_functions(self, code):
pass
......@@ -1667,6 +1677,8 @@ class CFuncDefNode(FuncDefNode):
for arg in self.type.args:
if arg.needs_type_test:
self.generate_arg_type_test(arg, code)
elif arg.type.is_pyobject and not arg.accept_none:
self.generate_arg_none_check(arg, code)
def error_value(self):
if self.return_type.is_pyobject:
......@@ -1880,23 +1892,25 @@ class DefNode(FuncDefNode):
arg.needs_conversion = 0
arg.needs_type_test = 0
arg.is_generic = 1
if arg.type.is_extension_type or arg.type.is_builtin_type:
if arg.type.is_pyobject:
if arg.or_none:
arg.accept_none = True
elif arg.not_none:
arg.accept_none = False
else:
elif arg.type.is_extension_type or arg.type.is_builtin_type:
# default depends on compiler directive
arg.accept_none = allow_none_for_extension_args
else:
# probably just a plain 'object'
arg.accept_none = True
else:
arg.accept_none = True # won't be used, but must be there
if arg.not_none:
error(self.pos, "Only extension type arguments can have 'not None'")
error(self.pos, "Only Python type arguments can have 'not None'")
if arg.or_none:
error(self.pos, "Only extension type arguments can have 'or None'")
error(self.pos, "Only Python type arguments can have 'or None'")
def analyse_signature(self, env):
any_type_tests_needed = 0
if self.entry.is_special:
self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
......@@ -1941,7 +1955,6 @@ class DefNode(FuncDefNode):
if not arg.type.same_as(arg.hdr_type):
if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
arg.needs_type_test = 1
any_type_tests_needed = 1
else:
arg.needs_conversion = 1
if arg.needs_conversion:
......@@ -1959,9 +1972,6 @@ class DefNode(FuncDefNode):
if arg.is_generic and \
(arg.type.is_extension_type or arg.type.is_builtin_type):
arg.needs_type_test = 1
any_type_tests_needed = 1
if any_type_tests_needed:
env.use_utility_code(arg_type_test_utility_code)
def bad_signature(self):
sig = self.entry.signature
......@@ -2657,6 +2667,8 @@ class DefNode(FuncDefNode):
for arg in self.args:
if arg.needs_type_test:
self.generate_arg_type_test(arg, code)
elif not arg.accept_none and arg.type.is_pyobject:
self.generate_arg_none_check(arg, code)
def error_value(self):
return self.entry.signature.error_value
......
def eggs(int x not None, y not None):
def eggs(int x not None, char* y not None):
pass
_ERRORS = u"""
1:0: Only extension type arguments can have 'not None'
1:0: Only extension type arguments can have 'not None'
1:0: Only Python type arguments can have 'not None'
1:0: Only Python type arguments can have 'not None'
"""
......@@ -15,7 +15,7 @@ cdef attr(MyExtType x):
# defaults, without 'not/or None'
def ext_default(MyExtType x):
def ext_default(MyExtType x): # currently behaves like 'or None'
"""
>>> ext_default(MyExtType())
123
......@@ -76,7 +76,7 @@ cdef litem(list L, int item):
# defaults, without 'not/or None'
def builtin_default(list L):
def builtin_default(list L): # currently behaves like 'or None'
"""
>>> builtin_default([123])
123
......@@ -129,23 +129,75 @@ def builtin_not_none(list L not None):
return litem(L, 0)
## builtin type 'object' (which includes None!) - currently unclear!
## def object_or_none(object o or None):
## """
## >>> object_or_none([])
## list
## >>> object_or_none(None)
## NoneType
## """
## return type(o).__name__
## def object_not_none(object o not None):
## """
## >>> object_not_none([123])
## 123
## >>> object_not_none(None)
## Traceback (most recent call last):
## TypeError: Argument 'o' has incorrect type (expected object, got NoneType)
## """
## return type(o).__name__
## builtin type 'object' - isinstance(None, object) is True!
def object_default(object o): # behaves like 'or None'
"""
>>> object_default(object())
'object'
>>> object_default([])
'list'
>>> object_default(None)
'NoneType'
"""
return type(o).__name__
def object_or_none(object o or None):
"""
>>> object_or_none(object())
'object'
>>> object_or_none([])
'list'
>>> object_or_none(None)
'NoneType'
"""
return type(o).__name__
def object_not_none(object o not None):
"""
>>> object_not_none(object())
'object'
>>> object_not_none([])
'list'
>>> object_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'o' must not be None
"""
return type(o).__name__
## untyped 'object' - isinstance(None, object) is True!
def notype_default(o): # behaves like 'or None'
"""
>>> notype_default(object())
'object'
>>> notype_default([])
'list'
>>> notype_default(None)
'NoneType'
"""
return type(o).__name__
def notype_or_none(o or None):
"""
>>> notype_or_none(object())
'object'
>>> notype_or_none([])
'list'
>>> notype_or_none(None)
'NoneType'
"""
return type(o).__name__
def notype_not_none(o not None):
"""
>>> notype_not_none(object())
'object'
>>> notype_not_none([])
'list'
>>> notype_not_none(None)
Traceback (most recent call last):
TypeError: Argument 'o' must not be None
"""
return type(o).__name__
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