summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2018-09-29 19:08:13 +0200
committerStefan Behnel <stefan_ml@behnel.de>2018-09-29 19:08:13 +0200
commitc9eda12b4806fba3931f7b791be7a672c92d9ca0 (patch)
tree9d6416c9dc1fe67b09b5dea5a5a26a581456daa6
parentf75b8e8fc8ea3842cbf3ae22716fc5c3b4b96102 (diff)
downloadcython-c9eda12b4806fba3931f7b791be7a672c92d9ca0.tar.gz
Rename the options of the "check_size" feature to make them more obvious: "warn" warns, "error" fails, and "extend" silently allows extending.
Closes #2627.
-rw-r--r--Cython/Compiler/ModuleNode.py8
-rw-r--r--Cython/Compiler/Nodes.py4
-rw-r--r--Cython/Compiler/Parsing.py14
-rw-r--r--Cython/Compiler/PyrexTypes.py6
-rw-r--r--Cython/Compiler/Symtab.py2
-rw-r--r--Cython/Includes/numpy/__init__.pxd4
-rw-r--r--Cython/Utility/ImportExport.c10
-rw-r--r--docs/src/userguide/extension_types.rst17
-rw-r--r--tests/run/check_size.srctree51
9 files changed, 56 insertions, 60 deletions
diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py
index fd65855c2..c86a12263 100644
--- a/Cython/Compiler/ModuleNode.py
+++ b/Cython/Compiler/ModuleNode.py
@@ -3062,11 +3062,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# check_size
if not type.is_external or type.is_subclassed:
cs = 0
- elif type.check_size == 'min':
- cs = 1
- elif type.check_size == True:
+ elif type.check_size == 'error':
cs = 0
- elif type.check_size == False:
+ elif type.check_size == 'warn':
+ cs = 1
+ elif type.check_size == 'extend':
cs = 2
else:
raise RuntimeError("invalid value for check_size '%s' when compiling %s.%s" % (
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index dad9b70cd..48287b3fa 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -4630,7 +4630,7 @@ class CClassDefNode(ClassDefNode):
# bases TupleNode Base class(es)
# objstruct_name string or None Specified C name of object struct
# typeobj_name string or None Specified C name of type object
- # check_size 'min' or boolean What to do if tp_basicsize does not match
+ # check_size 'warn', 'error', 'extend' What to do if tp_basicsize does not match
# in_pxd boolean Is in a .pxd file
# decorators [DecoratorNode] list of decorators or None
# doc string or None
@@ -4647,7 +4647,7 @@ class CClassDefNode(ClassDefNode):
api = False
objstruct_name = None
typeobj_name = None
- check_size = 'min'
+ check_size = None
decorators = None
shadow = False
diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py
index 49bbba0c7..79dd1e04c 100644
--- a/Cython/Compiler/Parsing.py
+++ b/Cython/Compiler/Parsing.py
@@ -3512,8 +3512,6 @@ def p_c_class_definition(s, pos, ctx):
error(pos, "Type object name specification required for 'api' C class")
else:
error(pos, "Invalid class visibility '%s'" % ctx.visibility)
- if check_size is None:
- check_size = 'min' # TODO: move into 'CClassDefNode'
return Nodes.CClassDefNode(pos,
visibility = ctx.visibility,
typedef_flag = ctx.typedef_flag,
@@ -3547,18 +3545,12 @@ def p_c_class_options(s):
elif s.systring == 'check_size':
s.next()
check_size = p_ident(s)
- if check_size == 'False':
- check_size = False
- elif check_size == 'True':
- check_size = True
- elif check_size == 'min':
- pass
- else:
- s.error('Expected False, True, or min, not %r' % check_size)
+ if check_size not in ('extend', 'warn', 'error'):
+ s.error("Expected one of extend, warn or error, found %r" % check_size)
if s.sy != ',':
break
s.next()
- s.expect(']', "Expected 'object' or 'type'")
+ s.expect(']', "Expected 'object', 'type' or 'check_size'")
return objstruct_name, typeobj_name, check_size
diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py
index 54259ea50..f924e01b2 100644
--- a/Cython/Compiler/PyrexTypes.py
+++ b/Cython/Compiler/PyrexTypes.py
@@ -1345,7 +1345,7 @@ class PyExtensionType(PyObjectType):
# vtable_cname string Name of C method table definition
# early_init boolean Whether to initialize early (as opposed to during module execution).
# defered_declarations [thunk] Used to declare class hierarchies in order
- # check_size 'min' or boolean What to do if tp_basicsize does not match
+ # check_size 'warn', 'error', 'extend' What to do if tp_basicsize does not match
is_extension_type = 1
has_attributes = 1
@@ -1353,7 +1353,7 @@ class PyExtensionType(PyObjectType):
objtypedef_cname = None
- def __init__(self, name, typedef_flag, base_type, is_external=0, check_size='min'):
+ def __init__(self, name, typedef_flag, base_type, is_external=0, check_size=None):
self.name = name
self.scope = None
self.typedef_flag = typedef_flag
@@ -1369,7 +1369,7 @@ class PyExtensionType(PyObjectType):
self.vtabptr_cname = None
self.vtable_cname = None
self.is_external = is_external
- self.check_size = check_size
+ self.check_size = check_size or 'warn'
self.defered_declarations = []
def set_scope(self, scope):
diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py
index 743cd0ebf..e9606b58d 100644
--- a/Cython/Compiler/Symtab.py
+++ b/Cython/Compiler/Symtab.py
@@ -1482,7 +1482,7 @@ class ModuleScope(Scope):
def declare_c_class(self, name, pos, defining=0, implementing=0,
module_name=None, base_type=None, objstruct_cname=None,
typeobj_cname=None, typeptr_cname=None, visibility='private',
- typedef_flag=0, api=0, check_size='min',
+ typedef_flag=0, api=0, check_size=None,
buffer_defaults=None, shadow=0):
# If this is a non-extern typedef class, expose the typedef, but use
# the non-typedef struct internally to avoid needing forward
diff --git a/Cython/Includes/numpy/__init__.pxd b/Cython/Includes/numpy/__init__.pxd
index 11eee4e6e..4e5b15d4d 100644
--- a/Cython/Includes/numpy/__init__.pxd
+++ b/Cython/Includes/numpy/__init__.pxd
@@ -203,7 +203,7 @@ cdef extern from "numpy/arrayobject.h":
ctypedef struct PyArray_Descr:
pass
- ctypedef class numpy.dtype [object PyArray_Descr, check_size False]:
+ ctypedef class numpy.dtype [object PyArray_Descr, check_size extend]:
# Use PyDataType_* macros when possible, however there are no macros
# for accessing some of the fields, so some are defined.
cdef PyTypeObject* typeobj
@@ -239,7 +239,7 @@ cdef extern from "numpy/arrayobject.h":
# like PyArrayObject**.
pass
- ctypedef class numpy.ndarray [object PyArrayObject, check_size False]:
+ ctypedef class numpy.ndarray [object PyArrayObject, check_size extend]:
cdef __cythonbufferdefaults__ = {"mode": "strided"}
cdef:
diff --git a/Cython/Utility/ImportExport.c b/Cython/Utility/ImportExport.c
index 77ff3b850..9b2b4acfc 100644
--- a/Cython/Utility/ImportExport.c
+++ b/Cython/Utility/ImportExport.c
@@ -319,11 +319,11 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name,
size_t size, int check_size)
{
/*
- * check_size tells what to do if tp_basicsize is different from size:
- * 0 - Error (originates in check_size=True)
- * 1 - Error if tp_basicsize is smaller, warn if larger (originates in check_size='min')
- * 2 - Error if tp_basicsize is smaller (originates in check_size=False)
- */
+ * 'check_size' tells what to do if tp_basicsize is different from size:
+ * 0 - Error (originates in check_size=error)
+ * 1 - Error if tp_basicsize is smaller, warn if larger (originates in check_size=warn)
+ * 2 - Error if tp_basicsize is smaller, but allow compatible extensions (originates in check_size=extend)
+ */
PyObject *result = 0;
char warning[200];
Py_ssize_t basicsize;
diff --git a/docs/src/userguide/extension_types.rst b/docs/src/userguide/extension_types.rst
index 62f9a502b..b9cf890fb 100644
--- a/docs/src/userguide/extension_types.rst
+++ b/docs/src/userguide/extension_types.rst
@@ -771,14 +771,15 @@ Where:
- ``object_struct_name`` is the name to assume for the type's C struct.
- ``type_object_name`` is the name to assume for the type's statically
declared type object.
-- ``cs_option`` is ``min`` (the default), ``True``, or ``False`` and is only
- used for external extension types. If ``True``, ``sizeof(object_struct)`` must
- match the type's ``tp_basicsize``. If ``False``, or ``min``, the
- ``object_struct`` may be smaller than the type's ``tp_basicsize``, which
- indicates the type allocated at runtime may be part of an updated module, and
- that the external module's developers extended the object in a
- backward-compatible fashion (only adding new fields to the end of the
- object). If ``min``, a warning will be emitted.
+- ``cs_option`` is ``warn`` (the default), ``error``, or ``extend`` and is only
+ used for external extension types. If ``error``, the ``sizeof(object_struct)``
+ that was found at compile time must match the type's runtime ``tp_basicsize``
+ exactly, otherwise the module import will fail with an error. If ``warn``
+ or ``extend``, the ``object_struct`` is allowed to be smaller than the type's
+ ``tp_basicsize``, which indicates the runtime type may be part of an updated
+ module, and that the external module's developers extended the object in a
+ backward-compatible fashion (only adding new fields to the end of the object).
+ If ``warn``, a warning will be emitted in this case.
The clauses can be written in any order.
diff --git a/tests/run/check_size.srctree b/tests/run/check_size.srctree
index 8391534e4..4d82dd15d 100644
--- a/tests/run/check_size.srctree
+++ b/tests/run/check_size.srctree
@@ -13,7 +13,7 @@ setup(ext_modules= cythonize("check_size.pyx"))
setup(ext_modules = cythonize("_check_size*.pyx"))
try:
- setup(ext_modules= cythonize("check_size6.pyx"))
+ setup(ext_modules= cythonize("check_size_invalid.pyx"))
assert False
except CompileError as e:
pass
@@ -86,7 +86,7 @@ cdef class Foo:
self.field1 = f1
self.field2 = f2
-######## _check_size0.pyx ########
+######## _check_size_exact.pyx ########
cdef extern from "check_size_nominal.h":
@@ -99,7 +99,7 @@ cdef extern from "check_size_nominal.h":
cpdef public int testme(Foo f) except -1:
return f.f0 + f.f1
-######## _check_size1.pyx ########
+######## _check_size_too_small.pyx ########
cdef extern from "check_size_bigger.h":
@@ -114,7 +114,7 @@ cpdef public int testme(Foo f, int f2) except -1:
f.f2 = f2
return f.f0 + f.f1 + f.f2
-######## _check_size2.pyx ########
+######## _check_size_default.pyx ########
cdef extern from "check_size_smaller.h":
@@ -126,12 +126,12 @@ cdef extern from "check_size_smaller.h":
cpdef public int testme(Foo f) except -1:
return f.f9
-######## _check_size3.pyx ########
+######## _check_size_warn.pyx ########
cdef extern from "check_size_smaller.h":
- # make sure missing check_size is equivalent to min
- ctypedef class check_size.Foo [object FooStructSmall, check_size min]:
+ # make sure missing check_size is equivalent to warn
+ ctypedef class check_size.Foo [object FooStructSmall, check_size warn]:
cdef:
int f9
@@ -139,12 +139,12 @@ cdef extern from "check_size_smaller.h":
cpdef public int testme(Foo f) except -1:
return f.f9
-######## _check_size4.pyx ########
+######## _check_size_extend.pyx ########
cdef extern from "check_size_smaller.h":
- # Disable size check
- ctypedef class check_size.Foo [object FooStructSmall, check_size False]:
+ # Allow size to be larger
+ ctypedef class check_size.Foo [object FooStructSmall, check_size extend]:
cdef:
int f9
@@ -152,12 +152,12 @@ cdef extern from "check_size_smaller.h":
cpdef public int testme(Foo f) except -1:
return f.f9
-######## _check_size5.pyx ########
+######## _check_size_error.pyx ########
cdef extern from "check_size_smaller.h":
# Strict checking, will raise an error
- ctypedef class check_size.Foo [object FooStructSmall, check_size True]:
+ ctypedef class check_size.Foo [object FooStructSmall, check_size error]:
cdef:
int f9
@@ -165,12 +165,12 @@ cdef extern from "check_size_smaller.h":
cpdef public int testme(Foo f) except -1:
return f.f9
-######## check_size6.pyx ########
+######## check_size_invalid.pyx ########
cdef extern from "check_size_smaller.h":
- # Raise Compilerror when using bad value
- ctypedef class check_size.Foo [object FooStructSmall, check_size max]:
+ # Raise CompileError when using bad value
+ ctypedef class check_size.Foo [object FooStructSmall, check_size hihi]:
cdef:
int f9
@@ -180,20 +180,20 @@ cpdef public int testme(Foo f) except -1:
######## runner.py ########
-import check_size, _check_size0, warnings
+import check_size, _check_size_exact, warnings
foo = check_size.Foo(23, 123, 1023)
assert foo.field0 == 23
assert foo.field1 == 123
-ret = _check_size0.testme(foo)
+ret = _check_size_exact.testme(foo)
assert ret == 23 + 123
# ValueError since check_size.Foo's tp_basicsize is smaller than what is needed
# for FooStructBig. Messing with f2 will access memory outside the struct!
try:
- import _check_size1
+ import _check_size_too_small
assert False
except ValueError as e:
assert str(e).startswith('check_size.Foo size changed')
@@ -207,25 +207,28 @@ except ValueError as e:
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
- import _check_size2
- import _check_size3
+ import _check_size_default
+ import _check_size_warn
assert len(w) == 2, 'expected two warnings, got %d' % len(w)
assert str(w[0].message).startswith('check_size.Foo size changed')
assert str(w[1].message).startswith('check_size.Foo size changed')
-ret = _check_size2.testme(foo)
+ret = _check_size_default.testme(foo)
assert ret == 23
-ret = _check_size3.testme(foo)
+ret = _check_size_warn.testme(foo)
assert ret == 23
with warnings.catch_warnings(record=True) as w:
# No warning, runtime vendor must provide backward compatibility
- import _check_size4
+ import _check_size_extend
assert len(w) == 0
+ret = _check_size_extend.testme(foo)
+assert ret == 23
+
try:
# Enforce strict checking
- import _check_size5
+ import _check_size_error
assert False
except ValueError as e:
assert str(e).startswith('check_size.Foo size changed')