Commit 8193f74a authored by Mark Florisson's avatar Mark Florisson
parents 76567d05 43a3dbea
...@@ -38,3 +38,4 @@ ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1 ...@@ -38,3 +38,4 @@ ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1
7fa84cb6d3d75eb3d015aeeb60bf8b642171fe93 0.14.beta2 7fa84cb6d3d75eb3d015aeeb60bf8b642171fe93 0.14.beta2
8412b39fbc3eb709a543e2f1e95c0c8881ea9ed4 0.14.beta2 8412b39fbc3eb709a543e2f1e95c0c8881ea9ed4 0.14.beta2
a6b9f0a6d02d23fc3d3a9d0587867faa3afb2fcd 0.14.rc0 a6b9f0a6d02d23fc3d3a9d0587867faa3afb2fcd 0.14.rc0
15bf34c9387444e262acb1de594405444dd571a4 0.14
...@@ -220,7 +220,11 @@ def parse_dependencies(source_filename): ...@@ -220,7 +220,11 @@ def parse_dependencies(source_filename):
# Actual parsing is way to slow, so we use regular expressions. # Actual parsing is way to slow, so we use regular expressions.
# The only catch is that we must strip comments and string # The only catch is that we must strip comments and string
# literals ahead of time. # literals ahead of time.
source = Utils.open_source_file(source_filename, "rU").read() fh = Utils.open_source_file(source_filename, "rU")
try:
source = fh.read()
finally:
fh.close()
distutils_info = DistutilsInfo(source) distutils_info = DistutilsInfo(source)
source, literals = strip_string_literals(source) source, literals = strip_string_literals(source)
source = source.replace('\\\n', ' ') source = source.replace('\\\n', ' ')
......
...@@ -52,9 +52,12 @@ def unbound_symbols(code, context=None): ...@@ -52,9 +52,12 @@ def unbound_symbols(code, context=None):
symbol_collector = AllSymbols() symbol_collector = AllSymbols()
symbol_collector(tree) symbol_collector(tree)
unbound = [] unbound = []
import __builtin__ try:
import builtins
except ImportError:
import __builtin__ as builtins
for name in symbol_collector.names: for name in symbol_collector.names:
if not tree.scope.lookup(name) and not hasattr(__builtin__, name): if not tree.scope.lookup(name) and not hasattr(builtins, name):
unbound.append(name) unbound.append(name)
return unbound return unbound
...@@ -79,7 +82,7 @@ def safe_type(arg, context=None): ...@@ -79,7 +82,7 @@ def safe_type(arg, context=None):
return 'numpy.ndarray[numpy.%s_t, ndim=%s]' % (arg.dtype.name, arg.ndim) return 'numpy.ndarray[numpy.%s_t, ndim=%s]' % (arg.dtype.name, arg.ndim)
else: else:
for base_type in py_type.mro(): for base_type in py_type.mro():
if base_type.__module__ == '__builtin__': if base_type.__module__ in ('__builtin__', 'builtins'):
return 'object' return 'object'
module = context.find_module(base_type.__module__, need_pxd=False) module = context.find_module(base_type.__module__, need_pxd=False)
if module: if module:
...@@ -125,7 +128,7 @@ def cython_inline(code, ...@@ -125,7 +128,7 @@ def cython_inline(code,
arg_names.sort() arg_names.sort()
arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names]) arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names])
key = code, arg_sigs, sys.version_info, sys.executable, Cython.__version__ key = code, arg_sigs, sys.version_info, sys.executable, Cython.__version__
module_name = "_cython_inline_" + hashlib.md5(str(key)).hexdigest() module_name = "_cython_inline_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
try: try:
if not os.path.exists(lib_dir): if not os.path.exists(lib_dir):
os.makedirs(lib_dir) os.makedirs(lib_dir)
...@@ -160,7 +163,11 @@ def __invoke(%(params)s): ...@@ -160,7 +163,11 @@ def __invoke(%(params)s):
for key, value in literals.items(): for key, value in literals.items():
module_code = module_code.replace(key, value) module_code = module_code.replace(key, value)
pyx_file = os.path.join(lib_dir, module_name + '.pyx') pyx_file = os.path.join(lib_dir, module_name + '.pyx')
open(pyx_file, 'w').write(module_code) fh = open(pyx_file, 'w')
try:
fh.write(module_code)
finally:
fh.close()
extension = Extension( extension = Extension(
name = module_name, name = module_name,
sources = [pyx_file], sources = [pyx_file],
......
...@@ -44,7 +44,7 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -44,7 +44,7 @@ class AnnotationCCodeWriter(CCodeWriter):
if pos is not None: if pos is not None:
CCodeWriter.mark_pos(self, pos) CCodeWriter.mark_pos(self, pos)
if self.last_pos: if self.last_pos:
pos_code = self.code.setdefault(self.last_pos[0].get_description(),{}) pos_code = self.code.setdefault(self.last_pos[0].filename,{})
code = pos_code.get(self.last_pos[1], "") code = pos_code.get(self.last_pos[1], "")
pos_code[self.last_pos[1]] = code + self.annotation_buffer.getvalue() pos_code[self.last_pos[1]] = code + self.annotation_buffer.getvalue()
self.annotation_buffer = StringIO() self.annotation_buffer = StringIO()
......
...@@ -10,15 +10,15 @@ usage = """\ ...@@ -10,15 +10,15 @@ usage = """\
Cython (http://cython.org) is a compiler for code written in the Cython (http://cython.org) is a compiler for code written in the
Cython language. Cython is based on Pyrex by Greg Ewing. Cython language. Cython is based on Pyrex by Greg Ewing.
Usage: cython [options] sourcefile.pyx ... Usage: cython [options] sourcefile.{pyx,py} ...
Options: Options:
-V, --version Display version number of cython compiler -V, --version Display version number of cython compiler
-l, --create-listing Write error messages to a listing file -l, --create-listing Write error messages to a listing file
-I, --include-dir <directory> Search for include files in named directory -I, --include-dir <directory> Search for include files in named directory
(multiply include directories are allowed). (multiple include directories are allowed).
-o, --output-file <filename> Specify name of generated C file -o, --output-file <filename> Specify name of generated C file
-t, --timestamps Only compile newer source files (implied with -r) -t, --timestamps Only compile newer source files
-f, --force Compile all source files (overrides implied -t) -f, --force Compile all source files (overrides implied -t)
-q, --quiet Don't print module names in recursive mode -q, --quiet Don't print module names in recursive mode
-v, --verbose Be verbose, print file names on multiple compilation -v, --verbose Be verbose, print file names on multiple compilation
...@@ -30,11 +30,11 @@ Options: ...@@ -30,11 +30,11 @@ Options:
are searched from) are searched from)
--gdb Output debug information for cygdb --gdb Output debug information for cygdb
-D, --no-docstrings Remove docstrings. -D, --no-docstrings Strip docstrings from the compiled module.
-a, --annotate Produce a colorized HTML version of the source. -a, --annotate Produce a colorized HTML version of the source.
--line-directives Produce #line directives pointing to the .pyx source --line-directives Produce #line directives pointing to the .pyx source
--cplus Output a c++ rather than c file. --cplus Output a C++ rather than C file.
--embed Embed the Python interpreter in a main() method. --embed Generate a main() function that embeds the Python interpreter.
-2 Compile based on Python-2 syntax and code semantics. -2 Compile based on Python-2 syntax and code semantics.
-3 Compile based on Python-3 syntax and code semantics. -3 Compile based on Python-3 syntax and code semantics.
--fast-fail Abort the compilation on the first error --fast-fail Abort the compilation on the first error
...@@ -42,7 +42,7 @@ Options: ...@@ -42,7 +42,7 @@ Options:
""" """
# The following is broken http://trac.cython.org/cython_trac/ticket/379 # The following is broken http://trac.cython.org/cython_trac/ticket/379
# -r, --recursive Recursively find and compile dependencies # -r, --recursive Recursively find and compile dependencies (implies -t)
#The following experimental options are supported only on MacOSX: #The following experimental options are supported only on MacOSX:
...@@ -125,6 +125,8 @@ def parse_command_line(args): ...@@ -125,6 +125,8 @@ def parse_command_line(args):
options.language_level = 3 options.language_level = 3
elif option == "--fast-fail": elif option == "--fast-fail":
Options.fast_fail = True Options.fast_fail = True
elif option == "--disable-function-redefinition":
Options.disable_function_redefinition = True
elif option in ("-X", "--directive"): elif option in ("-X", "--directive"):
try: try:
options.compiler_directives = Options.parse_directive_list( options.compiler_directives = Options.parse_directive_list(
...@@ -141,6 +143,9 @@ def parse_command_line(args): ...@@ -141,6 +143,9 @@ def parse_command_line(args):
else: else:
sys.stderr.write("Unknown debug flag: %s\n" % option) sys.stderr.write("Unknown debug flag: %s\n" % option)
bad_usage() bad_usage()
elif option in ('-h', '--help'):
sys.stdout.write(usage)
sys.exit(0)
else: else:
sys.stderr.write("Unknown compiler flag: %s\n" % option) sys.stderr.write("Unknown compiler flag: %s\n" % option)
sys.exit(1) sys.exit(1)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
import cython import cython
cython.declare(re=object, Naming=object, Options=object, StringEncoding=object, cython.declare(re=object, Naming=object, Options=object, StringEncoding=object,
Utils=object, SourceDescriptor=object, StringIOTree=object, Utils=object, SourceDescriptor=object, StringIOTree=object,
DebugFlags=object, none_or_sub=object) DebugFlags=object, none_or_sub=object, basestring=object)
import re import re
import Naming import Naming
...@@ -19,9 +19,9 @@ import DebugFlags ...@@ -19,9 +19,9 @@ import DebugFlags
from Cython.Utils import none_or_sub from Cython.Utils import none_or_sub
try: try:
basestring from __builtin__ import basestring
except NameError: except ImportError:
basestring = str from builtins import str as basestring
class UtilityCode(object): class UtilityCode(object):
# Stores utility code to add during code generation. # Stores utility code to add during code generation.
......
...@@ -948,7 +948,8 @@ class BytesNode(ConstNode): ...@@ -948,7 +948,8 @@ class BytesNode(ConstNode):
# #
# value BytesLiteral # value BytesLiteral
type = PyrexTypes.c_char_ptr_type # start off as Python 'bytes' to support len() in O(1)
type = bytes_type
def compile_time_value(self, denv): def compile_time_value(self, denv):
return self.value return self.value
...@@ -969,11 +970,13 @@ class BytesNode(ConstNode): ...@@ -969,11 +970,13 @@ class BytesNode(ConstNode):
return len(self.value) == 1 return len(self.value) == 1
def coerce_to_boolean(self, env): def coerce_to_boolean(self, env):
# This is special because we start off as a C char*. Testing # This is special because testing a C char* for truth directly
# that for truth directly would yield the wrong result. # would yield the wrong result.
return BoolNode(self.pos, value=bool(self.value)) return BoolNode(self.pos, value=bool(self.value))
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if self.type == dst_type:
return self
if dst_type.is_int: if dst_type.is_int:
if not self.can_coerce_to_char_literal(): if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character string literals can be coerced into ints.") error(self.pos, "Only single-character string literals can be coerced into ints.")
...@@ -984,21 +987,20 @@ class BytesNode(ConstNode): ...@@ -984,21 +987,20 @@ class BytesNode(ConstNode):
return CharNode(self.pos, value=self.value) return CharNode(self.pos, value=self.value)
node = BytesNode(self.pos, value=self.value) node = BytesNode(self.pos, value=self.value)
if dst_type == PyrexTypes.c_char_ptr_type: if dst_type.is_pyobject:
node.type = PyrexTypes.c_char_ptr_type if dst_type in (py_object_type, Builtin.bytes_type):
node.type = Builtin.bytes_type
else:
self.check_for_coercion_error(dst_type, fail=True)
return node
elif dst_type == PyrexTypes.c_char_ptr_type:
node.type = dst_type
return node return node
elif dst_type == PyrexTypes.c_uchar_ptr_type: elif dst_type == PyrexTypes.c_uchar_ptr_type:
node.type = PyrexTypes.c_char_ptr_type node.type = PyrexTypes.c_char_ptr_type
return CastNode(node, PyrexTypes.c_uchar_ptr_type) return CastNode(node, PyrexTypes.c_uchar_ptr_type)
elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type):
if not self.type.is_pyobject: node.type = dst_type
if dst_type in (py_object_type, Builtin.bytes_type):
node.type = Builtin.bytes_type
elif dst_type.is_pyobject:
self.fail_assignment(dst_type)
return self
elif dst_type.is_pyobject and dst_type is not py_object_type:
self.check_for_coercion_error(dst_type, fail=True)
return node return node
# We still need to perform normal coerce_to processing on the # We still need to perform normal coerce_to processing on the
...@@ -1006,11 +1008,6 @@ class BytesNode(ConstNode): ...@@ -1006,11 +1008,6 @@ class BytesNode(ConstNode):
# in which case a type test node will be needed. # in which case a type test node will be needed.
return ConstNode.coerce_to(node, dst_type, env) return ConstNode.coerce_to(node, dst_type, env)
def as_py_string_node(self, env):
# Return a new BytesNode with the same value as this node
# but whose type is a Python type instead of a C type.
return BytesNode(self.pos, value = self.value, type = Builtin.bytes_type)
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
if self.type.is_pyobject: if self.type.is_pyobject:
self.result_code = code.get_py_string_const(self.value) self.result_code = code.get_py_string_const(self.value)
...@@ -1431,7 +1428,7 @@ class NameNode(AtomicExprNode): ...@@ -1431,7 +1428,7 @@ class NameNode(AtomicExprNode):
if self.is_used_as_rvalue: if self.is_used_as_rvalue:
entry = self.entry entry = self.entry
if entry.is_builtin: if entry.is_builtin:
# if not Options.cache_builtins: # cached builtins are ok if not Options.cache_builtins: # cached builtins are ok
self.gil_error() self.gil_error()
elif entry.is_pyglobal: elif entry.is_pyglobal:
self.gil_error() self.gil_error()
...@@ -2036,7 +2033,7 @@ class IndexNode(ExprNode): ...@@ -2036,7 +2033,7 @@ class IndexNode(ExprNode):
return None return None
def type_dependencies(self, env): def type_dependencies(self, env):
return self.base.type_dependencies(env) return self.base.type_dependencies(env) + self.index.type_dependencies(env)
def infer_type(self, env): def infer_type(self, env):
base_type = self.base.infer_type(env) base_type = self.base.infer_type(env)
...@@ -2605,6 +2602,7 @@ class SliceIndexNode(ExprNode): ...@@ -2605,6 +2602,7 @@ class SliceIndexNode(ExprNode):
self.start_code(), self.start_code(),
self.stop_code())) self.stop_code()))
self.generate_subexpr_disposal_code(code) self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
def generate_slice_guard_code(self, code, target_size): def generate_slice_guard_code(self, code, target_size):
if not self.base.type.is_array: if not self.base.type.is_array:
...@@ -2952,11 +2950,23 @@ class SimpleCallNode(CallNode): ...@@ -2952,11 +2950,23 @@ class SimpleCallNode(CallNode):
# Coerce arguments # Coerce arguments
for i in range(min(max_nargs, actual_nargs)): for i in range(min(max_nargs, actual_nargs)):
formal_type = func_type.args[i].type formal_type = func_type.args[i].type
self.args[i] = self.args[i].coerce_to(formal_type, env) arg = self.args[i].coerce_to(formal_type, env)
if arg.type.is_pyobject and not env.nogil and (arg.is_attribute or not arg.is_simple):
# we do not own the argument's reference, but we must
# make sure it cannot be collected before we return
# from the function, so we create an owned temp
# reference to it
arg = arg.coerce_to_temp(env)
self.args[i] = arg
for i in range(max_nargs, actual_nargs): for i in range(max_nargs, actual_nargs):
if self.args[i].type.is_pyobject: arg = self.args[i]
if arg.type.is_pyobject:
arg_ctype = arg.type.default_coerced_ctype()
if arg_ctype is None:
error(self.args[i].pos, error(self.args[i].pos,
"Python object cannot be passed as a varargs parameter") "Python object cannot be passed as a varargs parameter")
else:
self.args[i] = arg.coerce_to(arg_ctype, env)
# Calc result type and code fragment # Calc result type and code fragment
if isinstance(self.function, NewExprNode): if isinstance(self.function, NewExprNode):
self.type = PyrexTypes.CPtrType(self.function.class_type) self.type = PyrexTypes.CPtrType(self.function.class_type)
...@@ -3401,7 +3411,7 @@ class AttributeNode(ExprNode): ...@@ -3401,7 +3411,7 @@ class AttributeNode(ExprNode):
return module_scope.lookup_type(self.attribute) return module_scope.lookup_type(self.attribute)
if not isinstance(self.obj, (UnicodeNode, StringNode, BytesNode)): if not isinstance(self.obj, (UnicodeNode, StringNode, BytesNode)):
base_type = self.obj.analyse_as_type(env) base_type = self.obj.analyse_as_type(env)
if base_type and hasattr(base_type, 'scope'): if base_type and hasattr(base_type, 'scope') and base_type.scope is not None:
return base_type.scope.lookup_type(self.attribute) return base_type.scope.lookup_type(self.attribute)
return None return None
...@@ -8182,17 +8192,17 @@ typedef struct { ...@@ -8182,17 +8192,17 @@ typedef struct {
PyCFunctionObject func; PyCFunctionObject func;
} %(binding_cfunc)s_object; } %(binding_cfunc)s_object;
PyTypeObject %(binding_cfunc)s_type; static PyTypeObject %(binding_cfunc)s_type;
PyTypeObject *%(binding_cfunc)s = NULL; static PyTypeObject *%(binding_cfunc)s = NULL;
PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */ static PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */
#define %(binding_cfunc)s_New(ml, self) %(binding_cfunc)s_NewEx(ml, self, NULL) #define %(binding_cfunc)s_New(ml, self) %(binding_cfunc)s_NewEx(ml, self, NULL)
int %(binding_cfunc)s_init(void); /* proto */ static int %(binding_cfunc)s_init(void); /* proto */
""" % Naming.__dict__, """ % Naming.__dict__,
impl=""" impl="""
PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) { static PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
%(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s); %(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s);
if (op == NULL) if (op == NULL)
return NULL; return NULL;
...@@ -8218,7 +8228,7 @@ static PyObject *%(binding_cfunc)s_descr_get(PyObject *func, PyObject *obj, PyOb ...@@ -8218,7 +8228,7 @@ static PyObject *%(binding_cfunc)s_descr_get(PyObject *func, PyObject *obj, PyOb
return PyMethod_New(func, obj, type); return PyMethod_New(func, obj, type);
} }
int %(binding_cfunc)s_init(void) { static int %(binding_cfunc)s_init(void) {
%(binding_cfunc)s_type = PyCFunction_Type; %(binding_cfunc)s_type = PyCFunction_Type;
%(binding_cfunc)s_type.tp_name = __Pyx_NAMESTR("cython_binding_builtin_function_or_method"); %(binding_cfunc)s_type.tp_name = __Pyx_NAMESTR("cython_binding_builtin_function_or_method");
%(binding_cfunc)s_type.tp_dealloc = (destructor)%(binding_cfunc)s_dealloc; %(binding_cfunc)s_type.tp_dealloc = (destructor)%(binding_cfunc)s_dealloc;
......
...@@ -74,7 +74,6 @@ class Context(object): ...@@ -74,7 +74,6 @@ class Context(object):
# language_level int currently 2 or 3 for Python 2/3 # language_level int currently 2 or 3 for Python 2/3
def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2): def __init__(self, include_directories, compiler_directives, cpp=False, language_level=2):
#self.modules = {"__builtin__" : BuiltinScope()}
import Builtin, CythonScope import Builtin, CythonScope
self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules = {"__builtin__" : Builtin.builtin_scope}
self.modules["cython"] = CythonScope.create_cython_scope(self) self.modules["cython"] = CythonScope.create_cython_scope(self)
...@@ -99,6 +98,7 @@ class Context(object): ...@@ -99,6 +98,7 @@ class Context(object):
from Future import print_function, unicode_literals from Future import print_function, unicode_literals
self.future_directives.add(print_function) self.future_directives.add(print_function)
self.future_directives.add(unicode_literals) self.future_directives.add(unicode_literals)
self.modules['builtins'] = self.modules['__builtin__']
def create_pipeline(self, pxd, py=False): def create_pipeline(self, pxd, py=False):
from Visitor import PrintTree from Visitor import PrintTree
...@@ -315,7 +315,10 @@ class Context(object): ...@@ -315,7 +315,10 @@ class Context(object):
try: try:
if debug_find_module: if debug_find_module:
print("Context.find_module: Parsing %s" % pxd_pathname) print("Context.find_module: Parsing %s" % pxd_pathname)
source_desc = FileSourceDescriptor(pxd_pathname) rel_path = module_name.replace('.', os.sep) + os.path.splitext(pxd_pathname)[1]
if not pxd_pathname.endswith(rel_path):
rel_path = pxd_pathname # safety measure to prevent printing incorrect paths
source_desc = FileSourceDescriptor(pxd_pathname, rel_path)
err, result = self.process_pxd(source_desc, scope, module_name) err, result = self.process_pxd(source_desc, scope, module_name)
if err: if err:
raise err raise err
...@@ -589,15 +592,23 @@ def run_pipeline(source, options, full_module_name = None): ...@@ -589,15 +592,23 @@ def run_pipeline(source, options, full_module_name = None):
# Set up source object # Set up source object
cwd = os.getcwd() cwd = os.getcwd()
source_desc = FileSourceDescriptor(os.path.join(cwd, source)) abs_path = os.path.abspath(source)
source_ext = os.path.splitext(source)[1]
full_module_name = full_module_name or context.extract_module_name(source, options) full_module_name = full_module_name or context.extract_module_name(source, options)
if options.relative_path_in_code_position_comments:
rel_path = full_module_name.replace('.', os.sep) + source_ext
if not abs_path.endswith(rel_path):
rel_path = source # safety measure to prevent printing incorrect paths
else:
rel_path = abs_path
source_desc = FileSourceDescriptor(abs_path, rel_path)
source = CompilationSource(source_desc, full_module_name, cwd) source = CompilationSource(source_desc, full_module_name, cwd)
# Set up result object # Set up result object
result = create_default_resultobj(source, options) result = create_default_resultobj(source, options)
# Get pipeline # Get pipeline
if source_desc.filename.endswith(".py"): if source_ext.lower() == '.py':
pipeline = context.create_py_pipeline(options, result) pipeline = context.create_py_pipeline(options, result)
else: else:
pipeline = context.create_pyx_pipeline(options, result) pipeline = context.create_pyx_pipeline(options, result)
...@@ -825,6 +836,7 @@ default_options = dict( ...@@ -825,6 +836,7 @@ default_options = dict(
compiler_directives = {}, compiler_directives = {},
evaluate_tree_assertions = False, evaluate_tree_assertions = False,
emit_linenums = False, emit_linenums = False,
relative_path_in_code_position_comments = True,
language_level = 2, language_level = 2,
gdb_debug = False, gdb_debug = False,
) )
...@@ -139,7 +139,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -139,7 +139,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
h_code.putln("") h_code.putln("")
h_code.putln("#endif") h_code.putln("#endif")
h_code.copyto(open_new_file(result.h_file)) f = open_new_file(result.h_file)
try:
h_code.copyto(f)
finally:
f.close()
def generate_public_declaration(self, entry, h_code, i_code): def generate_public_declaration(self, entry, h_code, i_code):
h_code.putln("%s %s;" % ( h_code.putln("%s %s;" % (
...@@ -222,7 +226,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -222,7 +226,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
h_code.putln("") h_code.putln("")
h_code.putln("#endif") h_code.putln("#endif")
h_code.copyto(open_new_file(result.api_file)) f = open_new_file(result.api_file)
try:
h_code.copyto(f)
finally:
f.close()
def generate_cclass_header_code(self, type, h_code): def generate_cclass_header_code(self, type, h_code):
h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % ( h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
...@@ -264,7 +272,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -264,7 +272,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code = globalstate['before_global_var'] code = globalstate['before_global_var']
code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name) code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
code.putln("int %s%s = 0;" % (Naming.module_is_main, self.full_module_name.replace('.', '__'))) code.putln("static int %s%s = 0;" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) code.putln("/* Implementation of %s */" % env.qualified_name)
...@@ -569,14 +577,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -569,14 +577,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#define PyBytes_Repr PyString_Repr #define PyBytes_Repr PyString_Repr
#define PyBytes_Concat PyString_Concat #define PyBytes_Concat PyString_Concat
#define PyBytes_ConcatAndDel PyString_ConcatAndDel #define PyBytes_ConcatAndDel PyString_ConcatAndDel
#endif
#if PY_VERSION_HEX < 0x02060000
#define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type) #define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type)
#define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type) #define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type)
#endif #endif
#ifndef PySet_CheckExact #ifndef PySet_CheckExact
# define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type)
#endif #endif
#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
#define PyIntObject PyLongObject #define PyIntObject PyLongObject
#define PyInt_Type PyLong_Type #define PyInt_Type PyLong_Type
...@@ -858,7 +870,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -858,7 +870,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
Naming.extern_c_macro, Naming.extern_c_macro,
name)) name))
elif entry.visibility == 'public': elif entry.visibility == 'public':
#code.putln("DL_EXPORT(PyTypeObject) %s;" % name)
code.putln("%s DL_EXPORT(PyTypeObject) %s;" % ( code.putln("%s DL_EXPORT(PyTypeObject) %s;" % (
Naming.extern_c_macro, Naming.extern_c_macro,
name)) name))
...@@ -1591,8 +1602,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1591,8 +1602,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if entry.visibility == 'public': if entry.visibility == 'public':
header = "DL_EXPORT(PyTypeObject) %s = {" header = "DL_EXPORT(PyTypeObject) %s = {"
else: else:
#header = "statichere PyTypeObject %s = {" header = "static PyTypeObject %s = {"
header = "PyTypeObject %s = {"
#code.putln(header % scope.parent_type.typeobj_cname) #code.putln(header % scope.parent_type.typeobj_cname)
code.putln(header % type.typeobj_cname) code.putln(header % type.typeobj_cname)
code.putln( code.putln(
...@@ -2041,12 +2051,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2041,12 +2051,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.error_goto_if_null(type.typeptr_cname, pos)) code.error_goto_if_null(type.typeptr_cname, pos))
self.use_type_import_utility_code(env) self.use_type_import_utility_code(env)
if type.vtabptr_cname: if type.vtabptr_cname:
code.putln(
"if (__Pyx_GetVtable(%s->tp_dict, &%s) < 0) %s" % (
type.typeptr_cname,
type.vtabptr_cname,
code.error_goto(pos)))
env.use_utility_code(Nodes.get_vtable_utility_code) env.use_utility_code(Nodes.get_vtable_utility_code)
code.putln("%s = (struct %s*)__Pyx_GetVtable(%s->tp_dict); %s" % (
type.vtabptr_cname,
type.vtabstruct_cname,
type.typeptr_cname,
code.error_goto_if_null(type.vtabptr_cname, pos)))
env.types_imported[type] = 1 env.types_imported[type] = 1
py3_type_name_map = {'str' : 'bytes', 'unicode' : 'str'} py3_type_name_map = {'str' : 'bytes', 'unicode' : 'str'}
...@@ -2099,24 +2109,24 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2099,24 +2109,24 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# a significant performance hit. (See trac #561.) # a significant performance hit. (See trac #561.)
for func in entry.type.scope.pyfunc_entries: for func in entry.type.scope.pyfunc_entries:
if func.is_special and Options.docstrings and func.wrapperbase_cname: if func.is_special and Options.docstrings and func.wrapperbase_cname:
code.putln("{"); code.putln("{")
code.putln( code.putln(
'PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&%s, "%s"); %s' % ( 'PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&%s, "%s"); %s' % (
typeobj_cname, typeobj_cname,
func.name, func.name,
code.error_goto_if_null('wrapper', entry.pos))); code.error_goto_if_null('wrapper', entry.pos)))
code.putln( code.putln(
"if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {"); "if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) {")
code.putln( code.putln(
"%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % ( "%s = *((PyWrapperDescrObject *)wrapper)->d_base;" % (
func.wrapperbase_cname)); func.wrapperbase_cname))
code.putln( code.putln(
"%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname)); "%s.doc = %s;" % (func.wrapperbase_cname, func.doc_cname))
code.putln( code.putln(
"((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % ( "((PyWrapperDescrObject *)wrapper)->d_base = &%s;" % (
func.wrapperbase_cname)); func.wrapperbase_cname))
code.putln("}"); code.putln("}")
code.putln("}"); code.putln("}")
if type.vtable_cname: if type.vtable_cname:
code.putln( code.putln(
"if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % ( "if (__Pyx_SetVtable(%s.tp_dict, %s) < 0) %s" % (
......
...@@ -1353,7 +1353,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1353,7 +1353,7 @@ class FuncDefNode(StatNode, BlockNode):
# incref it to properly keep track of refcounts. # incref it to properly keep track of refcounts.
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
if entry.type.is_pyobject: if entry.type.is_pyobject:
if entry.assignments and not entry.in_closure: if (acquire_gil or entry.assignments) and not entry.in_closure:
code.put_var_incref(entry) code.put_var_incref(entry)
# ----- Initialise local variables # ----- Initialise local variables
for entry in lenv.var_entries: for entry in lenv.var_entries:
...@@ -1463,7 +1463,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1463,7 +1463,7 @@ class FuncDefNode(StatNode, BlockNode):
if entry.type.is_pyobject: if entry.type.is_pyobject:
if entry.in_closure: if entry.in_closure:
code.put_var_giveref(entry) code.put_var_giveref(entry)
elif entry.assignments: elif acquire_gil or entry.assignments:
code.put_var_decref(entry) code.put_var_decref(entry)
if self.needs_closure: if self.needs_closure:
code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type) code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
...@@ -1988,7 +1988,7 @@ class DefNode(FuncDefNode): ...@@ -1988,7 +1988,7 @@ class DefNode(FuncDefNode):
# staticmethod() was overridden - not much we can do here ... # staticmethod() was overridden - not much we can do here ...
self.is_staticmethod = False self.is_staticmethod = False
if self.name == '__new__': if self.name == '__new__' and env.is_py_class_scope:
self.is_staticmethod = 1 self.is_staticmethod = 1
self.analyse_argument_types(env) self.analyse_argument_types(env)
...@@ -2440,8 +2440,6 @@ class DefNode(FuncDefNode): ...@@ -2440,8 +2440,6 @@ class DefNode(FuncDefNode):
self.name, Naming.args_cname, self.error_value())) self.name, Naming.args_cname, self.error_value()))
code.putln("}") code.putln("}")
code.globalstate.use_utility_code(keyword_string_check_utility_code)
if self.starstar_arg: if self.starstar_arg:
if self.star_arg: if self.star_arg:
kwarg_check = "unlikely(%s)" % Naming.kwds_cname kwarg_check = "unlikely(%s)" % Naming.kwds_cname
...@@ -2450,6 +2448,7 @@ class DefNode(FuncDefNode): ...@@ -2450,6 +2448,7 @@ class DefNode(FuncDefNode):
else: else:
kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % ( kwarg_check = "unlikely(%s) && unlikely(PyDict_Size(%s) > 0)" % (
Naming.kwds_cname, Naming.kwds_cname) Naming.kwds_cname, Naming.kwds_cname)
code.globalstate.use_utility_code(keyword_string_check_utility_code)
code.putln( code.putln(
"if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % ( "if (%s && unlikely(!__Pyx_CheckKeywordStrings(%s, \"%s\", %d))) return %s;" % (
kwarg_check, Naming.kwds_cname, self.name, kwarg_check, Naming.kwds_cname, self.name,
...@@ -2513,8 +2512,6 @@ class DefNode(FuncDefNode): ...@@ -2513,8 +2512,6 @@ class DefNode(FuncDefNode):
has_fixed_positional_count = not self.star_arg and \ has_fixed_positional_count = not self.star_arg and \
min_positional_args == max_positional_args min_positional_args == max_positional_args
code.globalstate.use_utility_code(raise_double_keywords_utility_code)
code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
if self.num_required_kw_args: if self.num_required_kw_args:
code.globalstate.use_utility_code(raise_keyword_required_utility_code) code.globalstate.use_utility_code(raise_keyword_required_utility_code)
...@@ -2605,6 +2602,7 @@ class DefNode(FuncDefNode): ...@@ -2605,6 +2602,7 @@ class DefNode(FuncDefNode):
if code.label_used(argtuple_error_label): if code.label_used(argtuple_error_label):
code.put_goto(success_label) code.put_goto(success_label)
code.put_label(argtuple_error_label) code.put_label(argtuple_error_label)
code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % ( code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
self.name, has_fixed_positional_count, self.name, has_fixed_positional_count,
min_positional_args, max_positional_args, min_positional_args, max_positional_args,
...@@ -2727,6 +2725,7 @@ class DefNode(FuncDefNode): ...@@ -2727,6 +2725,7 @@ class DefNode(FuncDefNode):
# kwargs) that were passed into positional # kwargs) that were passed into positional
# arguments up to this point # arguments up to this point
code.putln('else {') code.putln('else {')
code.globalstate.use_utility_code(raise_argtuple_invalid_utility_code)
code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % ( code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
self.name, has_fixed_positional_count, self.name, has_fixed_positional_count,
min_positional_args, max_positional_args, i)) min_positional_args, max_positional_args, i))
...@@ -3346,6 +3345,12 @@ class ExprStatNode(StatNode): ...@@ -3346,6 +3345,12 @@ class ExprStatNode(StatNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.expr.analyse_expressions(env) self.expr.analyse_expressions(env)
def nogil_check(self, env):
if self.expr.type.is_pyobject and self.expr.is_temp:
self.gil_error()
gil_message = "Discarding owned Python object"
def generate_execution_code(self, code): def generate_execution_code(self, code):
self.expr.generate_evaluation_code(code) self.expr.generate_evaluation_code(code)
if not self.expr.is_temp and self.expr.result(): if not self.expr.is_temp and self.expr.result():
...@@ -6094,7 +6099,8 @@ invalid_keyword: ...@@ -6094,7 +6099,8 @@ invalid_keyword:
bad: bad:
return -1; return -1;
} }
""") """,
requires=[raise_double_keywords_utility_code])
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
...@@ -6238,25 +6244,26 @@ bad: ...@@ -6238,25 +6244,26 @@ bad:
get_vtable_utility_code = UtilityCode( get_vtable_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/ static void* __Pyx_GetVtable(PyObject *dict); /*proto*/
""", """,
impl = r""" impl = r"""
static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) { static void* __Pyx_GetVtable(PyObject *dict) {
void* ptr;
PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__"); PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!ob) if (!ob)
goto bad; goto bad;
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0) #if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
*(void **)vtabptr = PyCapsule_GetPointer(ob, 0); ptr = PyCapsule_GetPointer(ob, 0);
#else #else
*(void **)vtabptr = PyCObject_AsVoidPtr(ob); ptr = PyCObject_AsVoidPtr(ob);
#endif #endif
if (!*(void **)vtabptr) if (!ptr && !PyErr_Occurred())
goto bad; PyErr_SetString(PyExc_RuntimeError, "invalid vtable found for imported type");
Py_DECREF(ob); Py_DECREF(ob);
return 0; return ptr;
bad: bad:
Py_XDECREF(ob); Py_XDECREF(ob);
return -1; return NULL;
} }
""") """)
......
...@@ -1110,8 +1110,9 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): ...@@ -1110,8 +1110,9 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
def _function_is_builtin_name(self, function): def _function_is_builtin_name(self, function):
if not function.is_name: if not function.is_name:
return False return False
entry = self.current_env().lookup(function.name) env = self.current_env()
if entry and getattr(entry, 'scope', None) is not Builtin.builtin_scope: entry = env.lookup(function.name)
if entry is not env.builtin_scope().lookup_here(function.name):
return False return False
# if entry is None, it's at least an undeclared name, so likely builtin # if entry is None, it's at least an undeclared name, so likely builtin
return True return True
...@@ -1724,8 +1725,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1724,8 +1725,8 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
# into a C function call (defined in the builtin scope) # into a C function call (defined in the builtin scope)
if not function.entry: if not function.entry:
return node return node
is_builtin = function.entry.is_builtin \ is_builtin = function.entry.is_builtin or \
or getattr(function.entry, 'scope', None) is Builtin.builtin_scope function.entry is self.current_env().builtin_scope().lookup_here(function.name)
if not is_builtin: if not is_builtin:
return node return node
function_handler = self._find_handler( function_handler = self._find_handler(
...@@ -1985,20 +1986,26 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1985,20 +1986,26 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
test_nodes = [] test_nodes = []
env = self.current_env() env = self.current_env()
for test_type_node in types: for test_type_node in types:
if not test_type_node.entry: builtin_type = None
return node if isinstance(test_type_node, ExprNodes.NameNode):
if test_type_node.entry:
entry = env.lookup(test_type_node.entry.name) entry = env.lookup(test_type_node.entry.name)
if not entry or not entry.type or not entry.type.is_builtin_type: if entry and entry.type and entry.type.is_builtin_type:
return node builtin_type = entry.type
if builtin_type and builtin_type is not Builtin.type_type:
type_check_function = entry.type.type_check_function(exact=False) type_check_function = entry.type.type_check_function(exact=False)
if not type_check_function: type_check_args = [arg]
elif test_type_node.type is Builtin.type_type:
type_check_function = '__Pyx_TypeCheck'
type_check_args = [arg, test_type_node]
else:
return node return node
if type_check_function not in tests: if type_check_function not in tests:
tests.append(type_check_function) tests.append(type_check_function)
test_nodes.append( test_nodes.append(
ExprNodes.PythonCapiCallNode( ExprNodes.PythonCapiCallNode(
test_type_node.pos, type_check_function, self.Py_type_check_func_type, test_type_node.pos, type_check_function, self.Py_type_check_func_type,
args = [arg], args = type_check_args,
is_temp = True, is_temp = True,
)) ))
......
...@@ -51,6 +51,10 @@ c_line_in_traceback = 1 ...@@ -51,6 +51,10 @@ c_line_in_traceback = 1
# executes the body of this module. # executes the body of this module.
embed = False embed = False
# Disables function redefinition, allowing all functions to be declared at
# module creation time. For legacy code only.
disable_function_redefinition = False
# Declare compiler directives # Declare compiler directives
directive_defaults = { directive_defaults = {
......
...@@ -353,6 +353,10 @@ class PyObjectType(PyrexType): ...@@ -353,6 +353,10 @@ class PyObjectType(PyrexType):
def can_coerce_to_pyobject(self, env): def can_coerce_to_pyobject(self, env):
return True return True
def default_coerced_ctype(self):
"The default C type that this Python type coerces to, or None."
return None
def assignable_from(self, src_type): def assignable_from(self, src_type):
# except for pointers, conversion will be attempted # except for pointers, conversion will be attempted
return not src_type.is_ptr or src_type.is_string return not src_type.is_ptr or src_type.is_string
...@@ -404,6 +408,15 @@ class BuiltinObjectType(PyObjectType): ...@@ -404,6 +408,15 @@ class BuiltinObjectType(PyObjectType):
def __repr__(self): def __repr__(self):
return "<%s>"% self.cname return "<%s>"% self.cname
def default_coerced_ctype(self):
if self.name == 'bytes':
return c_char_ptr_type
elif self.name == 'bool':
return c_bint_type
elif self.name == 'float':
return c_double_type
return None
def assignable_from(self, src_type): def assignable_from(self, src_type):
if isinstance(src_type, BuiltinObjectType): if isinstance(src_type, BuiltinObjectType):
return src_type.name == self.name return src_type.name == self.name
...@@ -1371,10 +1384,10 @@ impl=""" ...@@ -1371,10 +1384,10 @@ impl="""
} }
#if %(is_float)s #if %(is_float)s
static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) { static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
#if HAVE_HYPOT #if !defined(HAVE_HYPOT) || defined(_MSC_VER)
return hypot%(m)s(z.real, z.imag);
#else
return sqrt%(m)s(z.real*z.real + z.imag*z.imag); return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
#else
return hypot%(m)s(z.real, z.imag);
#endif #endif
} }
static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s a, %(type)s b) { static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s a, %(type)s b) {
......
...@@ -166,8 +166,9 @@ class FileSourceDescriptor(SourceDescriptor): ...@@ -166,8 +166,9 @@ class FileSourceDescriptor(SourceDescriptor):
optional name argument and will be passed back when asking for optional name argument and will be passed back when asking for
the position()-tuple. the position()-tuple.
""" """
def __init__(self, filename): def __init__(self, filename, path_description=None):
filename = Utils.decode_filename(filename) filename = Utils.decode_filename(filename)
self.path_description = path_description or filename
self.filename = filename self.filename = filename
self.set_file_type_from_name(filename) self.set_file_type_from_name(filename)
self._cmp_name = filename self._cmp_name = filename
...@@ -180,7 +181,7 @@ class FileSourceDescriptor(SourceDescriptor): ...@@ -180,7 +181,7 @@ class FileSourceDescriptor(SourceDescriptor):
require_normalised_newlines=False) require_normalised_newlines=False)
def get_description(self): def get_description(self):
return self.filename return self.path_description
def get_filenametable_entry(self): def get_filenametable_entry(self):
return self.filename return self.filename
...@@ -199,6 +200,8 @@ class StringSourceDescriptor(SourceDescriptor): ...@@ -199,6 +200,8 @@ class StringSourceDescriptor(SourceDescriptor):
Instances of this class can be used instead of a filenames if the Instances of this class can be used instead of a filenames if the
code originates from a string object. code originates from a string object.
""" """
filename = None
def __init__(self, name, code): def __init__(self, name, code):
self.name = name self.name = name
#self.set_file_type_from_name(name) #self.set_file_type_from_name(name)
......
...@@ -526,7 +526,7 @@ class Scope(object): ...@@ -526,7 +526,7 @@ class Scope(object):
def declare_pyfunction(self, name, pos, allow_redefine=False, visibility='extern'): def declare_pyfunction(self, name, pos, allow_redefine=False, visibility='extern'):
# Add an entry for a Python function. # Add an entry for a Python function.
entry = self.lookup_here(name) entry = self.lookup_here(name)
if not allow_redefine: if not allow_redefine or Options.disable_function_redefinition:
return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry) return self._declare_pyfunction(name, pos, visibility=visibility, entry=entry)
if entry: if entry:
if entry.type.is_unspecified: if entry.type.is_unspecified:
...@@ -733,6 +733,13 @@ class BuiltinScope(Scope): ...@@ -733,6 +733,13 @@ class BuiltinScope(Scope):
cname, type = definition cname, type = definition
self.declare_var(name, type, None, cname) self.declare_var(name, type, None, cname)
def lookup(self, name, language_level=None):
# 'language_level' is passed by ModuleScope
if language_level == 3:
if name == 'str':
name = 'unicode'
return Scope.lookup(self, name)
def declare_builtin(self, name, pos): def declare_builtin(self, name, pos):
if not hasattr(builtins, name): if not hasattr(builtins, name):
if self.outer_scope is not None: if self.outer_scope is not None:
...@@ -882,6 +889,12 @@ class ModuleScope(Scope): ...@@ -882,6 +889,12 @@ class ModuleScope(Scope):
def global_scope(self): def global_scope(self):
return self return self
def lookup(self, name):
entry = self.lookup_here(name)
if entry is not None:
return entry
return self.outer_scope.lookup(name, language_level = self.context.language_level)
def declare_builtin(self, name, pos): def declare_builtin(self, name, pos):
if not hasattr(builtins, name) and name != 'xrange': if not hasattr(builtins, name) and name != 'xrange':
# 'xrange' is special cased in Code.py # 'xrange' is special cased in Code.py
...@@ -1121,6 +1134,19 @@ class ModuleScope(Scope): ...@@ -1121,6 +1134,19 @@ class ModuleScope(Scope):
type.vtabslot_cname = "%s.%s" % ( type.vtabslot_cname = "%s.%s" % (
Naming.obj_base_cname, type.base_type.vtabslot_cname) Naming.obj_base_cname, type.base_type.vtabslot_cname)
elif type.scope and type.scope.cfunc_entries: elif type.scope and type.scope.cfunc_entries:
# one special case here: when inheriting from builtin
# types, the methods may also be built-in, in which
# case they won't need a vtable
entry_count = len(type.scope.cfunc_entries)
base_type = type.base_type
while base_type:
# FIXME: this will break if we ever get non-inherited C methods
if not base_type.scope or entry_count > len(base_type.scope.cfunc_entries):
break
if base_type.is_builtin_type:
# builtin base type defines all methods => no vtable needed
return
base_type = base_type.base_type
#print "...allocating vtabslot_cname because there are C methods" ### #print "...allocating vtabslot_cname because there are C methods" ###
type.vtabslot_cname = Naming.vtabslot_cname type.vtabslot_cname = Naming.vtabslot_cname
if type.vtabslot_cname: if type.vtabslot_cname:
...@@ -1535,9 +1561,8 @@ class CClassScope(ClassScope): ...@@ -1535,9 +1561,8 @@ class CClassScope(ClassScope):
if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'): if name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
error(pos, "Special method %s must be implemented via __richcmp__" % name) error(pos, "Special method %s must be implemented via __richcmp__" % name)
if name == "__new__": if name == "__new__":
warning(pos, "__new__ method of extension type will change semantics " error(pos, "__new__ method of extension type will change semantics "
"in a future version of Pyrex and Cython. Use __cinit__ instead.") "in a future version of Pyrex and Cython. Use __cinit__ instead.")
name = EncodedString("__cinit__")
entry = self.declare_var(name, py_object_type, pos, visibility='extern') entry = self.declare_var(name, py_object_type, pos, visibility='extern')
special_sig = get_special_method_signature(name) special_sig = get_special_method_signature(name)
if special_sig: if special_sig:
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import re import re
from StringIO import StringIO from StringIO import StringIO
from Scanning import PyrexScanner, StringSourceDescriptor from Scanning import PyrexScanner, StringSourceDescriptor
from Symtab import BuiltinScope, ModuleScope from Symtab import ModuleScope
import Symtab import Symtab
import PyrexTypes import PyrexTypes
from Visitor import VisitorTransform from Visitor import VisitorTransform
......
...@@ -226,6 +226,8 @@ class build_ext(_build_ext.build_ext): ...@@ -226,6 +226,8 @@ class build_ext(_build_ext.build_ext):
if not self.inplace and (self.pyrex_c_in_temp if not self.inplace and (self.pyrex_c_in_temp
or getattr(extension, 'pyrex_c_in_temp', 0)): or getattr(extension, 'pyrex_c_in_temp', 0)):
target_dir = os.path.join(self.build_temp, "pyrex") target_dir = os.path.join(self.build_temp, "pyrex")
for package_name in extension.name.split('.')[:-1]:
target_dir = os.path.join(target_dir, package_name)
else: else:
target_dir = None target_dir = None
......
...@@ -49,9 +49,9 @@ cdef extern from "Python.h": ...@@ -49,9 +49,9 @@ cdef extern from "Python.h":
# 0 is returned on success and -1 on error. # 0 is returned on success and -1 on error.
void PyBuffer_Release(object obj, object view) void PyBuffer_Release(Py_buffer *view)
# Release the buffer view over obj. This should be called when the # Release the buffer view. This should be called when the buffer
# buffer is no longer being used as it may free memory from it. # is no longer being used as it may free memory from it.
void* PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices) void* PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices)
# ?? # ??
......
__version__ = "0.14.rc0" __version__ = "0.14+"
# Void cython.* directives (for case insensitive operating systems). # Void cython.* directives (for case insensitive operating systems).
from Cython.Shadow import * from Cython.Shadow import *
include MANIFEST.in README.txt INSTALL.txt ToDo.txt USAGE.txt include MANIFEST.in README.txt INSTALL.txt ToDo.txt USAGE.txt
include COPYING.txt LICENSE.txt PKG-INFO Makefile include COPYING.txt LICENSE.txt Makefile
include .hgrev include .hgrev
include setup.py include setup.py
include setupegg.py include setupegg.py
...@@ -15,16 +15,12 @@ include Demos/callback/* ...@@ -15,16 +15,12 @@ include Demos/callback/*
include Demos/embed/* include Demos/embed/*
include Demos/freeze/* include Demos/freeze/*
include Demos/libraries/* include Demos/libraries/*
include Demos/Setup.py
include Demos/Makefile* include Demos/Makefile*
recursive-include Tools * recursive-include Tools *
recursive-include tests *.pyx *.pxd *.pxi *.py *.h *.BROKEN bugs.txt recursive-include tests *.pyx *.pxd *.pxi *.py *.h *.BROKEN bugs.txt
recursive-include tests *_lib.cpp *.srctree recursive-include tests *_lib.cpp *.srctree
include runtests.py include runtests.py
include Cython/Mac/Makefile
include Cython/Mac/_Filemodule_patched.c
include Cython/Debugger/Tests/cfuncs.c include Cython/Debugger/Tests/cfuncs.c
include Cython/Debugger/Tests/codefile include Cython/Debugger/Tests/codefile
......
...@@ -112,6 +112,7 @@ def handle_special_build(modname, pyxfilename): ...@@ -112,6 +112,7 @@ def handle_special_build(modname, pyxfilename):
return ext, setup_args return ext, setup_args
def handle_dependencies(pyxfilename): def handle_dependencies(pyxfilename):
testing = '_test_files' in globals()
dependfile = os.path.splitext(pyxfilename)[0] + PYXDEP_EXT dependfile = os.path.splitext(pyxfilename)[0] + PYXDEP_EXT
# by default let distutils decide whether to rebuild on its own # by default let distutils decide whether to rebuild on its own
...@@ -132,6 +133,7 @@ def handle_dependencies(pyxfilename): ...@@ -132,6 +133,7 @@ def handle_dependencies(pyxfilename):
files.extend(glob.glob(fullpath)) files.extend(glob.glob(fullpath))
# only for unit testing to see we did the right thing # only for unit testing to see we did the right thing
if testing:
_test_files[:] = [] #$pycheck_no _test_files[:] = [] #$pycheck_no
# if any file that the pyxfile depends upon is newer than # if any file that the pyxfile depends upon is newer than
...@@ -143,6 +145,7 @@ def handle_dependencies(pyxfilename): ...@@ -143,6 +145,7 @@ def handle_dependencies(pyxfilename):
print("Rebuilding because of ", file) print("Rebuilding because of ", file)
filetime = os.path.getmtime(file) filetime = os.path.getmtime(file)
os.utime(pyxfilename, (filetime, filetime)) os.utime(pyxfilename, (filetime, filetime))
if testing:
_test_files.append(file) _test_files.append(file)
def build_module(name, pyxfilename, pyxbuild_dir=None): def build_module(name, pyxfilename, pyxbuild_dir=None):
......
import pyximport; pyximport.install() import pyximport; pyximport.install(reload_support=True)
import os, sys import os, sys
import time, shutil import time, shutil
import tempfile import tempfile
...@@ -21,6 +21,7 @@ def on_remove_file_error(func, path, excinfo): ...@@ -21,6 +21,7 @@ def on_remove_file_error(func, path, excinfo):
print "You may want to delete this yourself when you get a chance." print "You may want to delete this yourself when you get a chance."
def test(): def test():
pyximport._test_files = []
tempdir = make_tempdir() tempdir = make_tempdir()
sys.path.append(tempdir) sys.path.append(tempdir)
filename = os.path.join(tempdir, "dummy.pyx") filename = os.path.join(tempdir, "dummy.pyx")
......
...@@ -18,6 +18,7 @@ ipow_crash_T562 ...@@ -18,6 +18,7 @@ ipow_crash_T562
pure_mode_cmethod_inheritance_T583 pure_mode_cmethod_inheritance_T583
genexpr_iterable_lookup_T600 genexpr_iterable_lookup_T600
for_from_pyvar_loop_T601 for_from_pyvar_loop_T601
decorators_T593
# CPython regression tests that don't current work: # CPython regression tests that don't current work:
pyregr.test_threadsignals pyregr.test_threadsignals
......
...@@ -82,20 +82,26 @@ def ticket_338(): ...@@ -82,20 +82,26 @@ def ticket_338():
for obj from 0 <= obj < 4: for obj from 0 <= obj < 4:
pass pass
def bare_pyvar_name(object x):
with nogil:
x
# For m(), the important thing is that there are errors on all lines in the range 23-69 # For m(), the important thing is that there are errors on all lines in the range 23-69
# except these: 34, 44, 56, 58, 60, 62-64 # except these: 29, 34, 44, 56, 58, 60, 62-64
_ERRORS = u""" _ERRORS = u"""
1:5: Function with Python return type cannot be declared nogil 1:5: Function with Python return type cannot be declared nogil
4:5: Function declared nogil has Python locals or temporaries 4:5: Function declared nogil has Python locals or temporaries
6:6: Assignment of Python object not allowed without gil 6:6: Assignment of Python object not allowed without gil
9:5: Discarding owned Python object not allowed without gil
11:5: Function with Python return type cannot be declared nogil 11:5: Function with Python return type cannot be declared nogil
15:5: Calling gil-requiring function not allowed without gil 15:5: Calling gil-requiring function not allowed without gil
24:9: Calling gil-requiring function not allowed without gil 24:9: Calling gil-requiring function not allowed without gil
26:12: Assignment of Python object not allowed without gil 26:12: Assignment of Python object not allowed without gil
28:8: Discarding owned Python object not allowed without gil
28:16: Constructing complex number not allowed without gil 28:16: Constructing complex number not allowed without gil
29:12: Accessing Python global or builtin not allowed without gil
30:8: Backquote expression not allowed without gil 30:8: Backquote expression not allowed without gil
30:8: Discarding owned Python object not allowed without gil
30:9: Operation not allowed without gil 30:9: Operation not allowed without gil
31:15: Assignment of Python object not allowed without gil 31:15: Assignment of Python object not allowed without gil
31:15: Operation not allowed without gil 31:15: Operation not allowed without gil
...@@ -105,20 +111,30 @@ _ERRORS = u""" ...@@ -105,20 +111,30 @@ _ERRORS = u"""
32:25: Constructing Python list not allowed without gil 32:25: Constructing Python list not allowed without gil
32:25: Operation not allowed without gil 32:25: Operation not allowed without gil
33:17: Iterating over Python object not allowed without gil 33:17: Iterating over Python object not allowed without gil
35:11: Discarding owned Python object not allowed without gil
35:11: Indexing Python object not allowed without gil 35:11: Indexing Python object not allowed without gil
36:11: Discarding owned Python object not allowed without gil
36:11: Slicing Python object not allowed without gil 36:11: Slicing Python object not allowed without gil
37:11: Constructing Python slice object not allowed without gil 37:11: Constructing Python slice object not allowed without gil
37:11: Discarding owned Python object not allowed without gil
37:11: Indexing Python object not allowed without gil 37:11: Indexing Python object not allowed without gil
37:13: Converting to Python object not allowed without gil 37:13: Converting to Python object not allowed without gil
37:15: Converting to Python object not allowed without gil 37:15: Converting to Python object not allowed without gil
37:17: Converting to Python object not allowed without gil 37:17: Converting to Python object not allowed without gil
38:11: Accessing Python attribute not allowed without gil 38:11: Accessing Python attribute not allowed without gil
39: 9: Constructing Python tuple not allowed without gil 38:11: Discarding owned Python object not allowed without gil
40: 8: Constructing Python list not allowed without gil 39:9: Constructing Python tuple not allowed without gil
41: 8: Constructing Python dict not allowed without gil 39:9: Discarding owned Python object not allowed without gil
40:8: Constructing Python list not allowed without gil
40:8: Discarding owned Python object not allowed without gil
41:8: Constructing Python dict not allowed without gil
41:8: Discarding owned Python object not allowed without gil
42:12: Discarding owned Python object not allowed without gil
42:12: Truth-testing Python object not allowed without gil 42:12: Truth-testing Python object not allowed without gil
43:13: Python type test not allowed without gil 43:13: Python type test not allowed without gil
45:10: Discarding owned Python object not allowed without gil
45:10: Operation not allowed without gil 45:10: Operation not allowed without gil
46:8: Discarding owned Python object not allowed without gil
46:8: Operation not allowed without gil 46:8: Operation not allowed without gil
47:10: Assignment of Python object not allowed without gil 47:10: Assignment of Python object not allowed without gil
47:14: Assignment of Python object not allowed without gil 47:14: Assignment of Python object not allowed without gil
......
...@@ -58,18 +58,18 @@ _ERRORS = u""" ...@@ -58,18 +58,18 @@ _ERRORS = u"""
30:22: Cannot convert Unicode string to 'bytes' implicitly, encoding required. 30:22: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
31:22: Cannot convert 'str' to 'bytes' implicitly. This is not portable. 31:22: Cannot convert 'str' to 'bytes' implicitly. This is not portable.
33:17: Cannot assign type 'char *' to 'str object' 33:17: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
34:19: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3. 34:19: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
35:17: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding. 35:17: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
36:19: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding. 36:19: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
38:20: str objects do not support coercion to unicode, use a unicode string literal instead (u'') 38:20: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
39:22: str objects do not support coercion to unicode, use a unicode string literal instead (u'') 39:22: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
40:20: Cannot assign type 'char *' to 'unicode object' 40:20: Cannot convert 'bytes' object to unicode implicitly, decoding required
41:22: Cannot convert 'bytes' object to unicode implicitly, decoding required 41:22: Cannot convert 'bytes' object to unicode implicitly, decoding required
42:22: Cannot convert 'char*' to unicode implicitly, decoding required 42:22: Cannot convert 'char*' to unicode implicitly, decoding required
44:19: Cannot assign type 'str object' to 'tuple object' 44:19: Cannot assign type 'str object' to 'tuple object'
45:18: Cannot assign type 'unicode object' to 'tuple object' 45:18: Cannot assign type 'unicode object' to 'tuple object'
46:18: Cannot assign type 'char *' to 'tuple object' 46:18: Cannot assign type 'bytes object' to 'tuple object'
""" """
...@@ -8,6 +8,35 @@ cdef class MyInt(int): ...@@ -8,6 +8,35 @@ cdef class MyInt(int):
""" """
cdef readonly object attr cdef readonly object attr
cdef class MyInt2(int):
"""
>>> MyInt2(2) == 2
True
>>> MyInt2(2).attr is None
True
>>> MyInt2(2).test(3)
5
"""
cdef readonly object attr
def test(self, arg):
return self._test(arg)
cdef _test(self, arg):
return self + arg
cdef class MyInt3(MyInt2):
"""
>>> MyInt3(2) == 2
True
>>> MyInt3(2).attr is None
True
>>> MyInt3(2).test(3)
6
"""
cdef _test(self, arg):
return self + arg + 1
cdef class MyFloat(float): cdef class MyFloat(float):
""" """
>>> MyFloat(1.0)== 1.0 >>> MyFloat(1.0)== 1.0
...@@ -23,6 +52,8 @@ cdef class MyUnicode(unicode): ...@@ -23,6 +52,8 @@ cdef class MyUnicode(unicode):
""" """
>>> MyUnicode(ustring) == ustring >>> MyUnicode(ustring) == ustring
True True
>>> MyUnicode(ustring + ustring) == ustring
False
>>> MyUnicode(ustring).attr is None >>> MyUnicode(ustring).attr is None
True True
""" """
...@@ -37,6 +68,43 @@ cdef class MyList(list): ...@@ -37,6 +68,43 @@ cdef class MyList(list):
""" """
cdef readonly object attr cdef readonly object attr
cdef class MyListOverride(list):
"""
>>> MyListOverride([1,2,3]) == [1,2,3]
True
>>> l = MyListOverride([1,2,3])
>>> l.reverse()
>>> l
[1, 2, 3, 5]
>>> l._reverse()
>>> l
[1, 2, 3, 5, 5]
"""
# not doctested:
"""
>>> l = MyListOverride([1,2,3])
>>> l.append(8)
>>> l
[1, 2, 3, 0, 8]
>>> l._append(9)
>>> l
[1, 2, 3, 0, 8, 0, 9]
"""
def reverse(self):
self[:] = self + [5]
def _reverse(self):
self.reverse()
## FIXME: this doesn't currently work:
## cdef int append(self, value) except -1:
## self[:] = self + [0] + [value]
## return 0
## def _append(self, value):
## self.append(value)
cdef class MyDict(dict): cdef class MyDict(dict):
""" """
>>> MyDict({1:2, 3:4}) == {1:2, 3:4} >>> MyDict({1:2, 3:4}) == {1:2, 3:4}
......
__doc__ = u"""
>>> d = Defined()
>>> n = NotDefined()
Traceback (most recent call last):
NameError: name 'NotDefined' is not defined
"""
if True:
class Defined(object):
"""
>>> isinstance(Defined(), Defined)
True
"""
if False:
class NotDefined(object):
"""
>>> NotDefined() # fails when defined
"""
def test_class_cond(x):
"""
>>> Test, test = test_class_cond(True)
>>> test.A
1
>>> Test().A
1
>>> Test, test = test_class_cond(False)
>>> test.A
2
>>> Test().A
2
"""
if x:
class Test(object):
A = 1
else:
class Test(object):
A = 2
return Test, Test()
def test_func_cond(x):
"""
>>> func = test_func_cond(True)
>>> func()
1
>>> func = test_func_cond(False)
>>> func()
2
"""
if x:
def func():
return 1
else:
def func():
return 2
return func
...@@ -28,8 +28,8 @@ def test_pow(double complex z, double complex w, tol=None): ...@@ -28,8 +28,8 @@ def test_pow(double complex z, double complex w, tol=None):
Various implementations produce slightly different results... Various implementations produce slightly different results...
>>> a = complex(3, 1) >>> a = complex(3, 1)
>>> test_pow(a, 1) >>> test_pow(a, 1, 1e-15)
(3+1j) True
>>> test_pow(a, 2, 1e-15) >>> test_pow(a, 2, 1e-15)
True True
>>> test_pow(a, a, 1e-15) >>> test_pow(a, a, 1e-15)
...@@ -48,7 +48,7 @@ def test_int_pow(double complex z, int n, tol=None): ...@@ -48,7 +48,7 @@ def test_int_pow(double complex z, int n, tol=None):
[True, True, True, True, True, True, True, True, True] [True, True, True, True, True, True, True, True, True]
>>> [test_int_pow(complex(0, 2), k, 1e-15) for k in range(-4, 5)] >>> [test_int_pow(complex(0, 2), k, 1e-15) for k in range(-4, 5)]
[True, True, True, True, True, True, True, True, True] [True, True, True, True, True, True, True, True, True]
>>> [test_int_pow(complex(2, 0.5), k, 1e-15) for k in range(0, 10)] >>> [test_int_pow(complex(2, 0.5), k, 1e-14) for k in range(0, 10)]
[True, True, True, True, True, True, True, True, True, True] [True, True, True, True, True, True, True, True, True, True]
""" """
if tol is None: if tol is None:
......
...@@ -66,6 +66,19 @@ def unicode_literals(): ...@@ -66,6 +66,19 @@ def unicode_literals():
print(isinstance(ustring, unicode) or type(ustring)) print(isinstance(ustring, unicode) or type(ustring))
return ustring return ustring
def str_type_is_unicode():
"""
>>> str_type, s = str_type_is_unicode()
>>> isinstance(s, type(ustring)) or (s, str_type)
True
>>> isinstance(s, str_type) or (s, str_type)
True
>>> isinstance(ustring, str_type) or str_type
True
"""
cdef str s = 'abc'
return str, s
def list_comp(): def list_comp():
""" """
>>> list_comp() >>> list_comp()
......
"""
>>> am_i_buggy
False
>>> Foo
False
"""
def testme(func):
try:
am_i_buggy
return True
except NameError:
return False
@testme
def am_i_buggy():
pass
def testclass(klass):
try:
Foo
return True
except NameError:
return False
@testclass
class Foo:
pass
def called_deco(a,b,c):
def count(f):
a.append( (b,c) )
return f
return count
L = []
@called_deco(L, 5, c=6)
@called_deco(L, c=3, b=4)
@called_deco(L, 1, 2)
def wrapped_func(x):
"""
>>> L
[(1, 2), (4, 3), (5, 6)]
>>> wrapped_func(99)
99
>>> L
[(1, 2), (4, 3), (5, 6)]
"""
return x
def class_in_closure(x):
"""
>>> C1, c0 = class_in_closure(5)
>>> C1().smeth1()
(5, ())
>>> C1.smeth1(1,2)
(5, (1, 2))
>>> C1.smeth1()
(5, ())
>>> c0.smeth0()
1
>>> c0.__class__.smeth0()
1
"""
class ClosureClass1(object):
@staticmethod
def smeth1(*args):
return x, args
class ClosureClass0(object):
@staticmethod
def smeth0():
return 1
return ClosureClass1, ClosureClass0()
def class_not_in_closure():
"""
>>> c = class_not_in_closure()
>>> c.smeth0()
1
>>> c.__class__.smeth0()
1
"""
class ClosureClass0(object):
@staticmethod
def smeth0():
return 1
return ClosureClass0()
class ODict(dict):
def __init__(self):
dict.__init__(self)
self._order = []
dict.__setitem__(self, '_order', self._order)
def __setitem__(self, key, value):
dict.__setitem__(self, key, value)
self._order.append(key)
class Base(type):
@staticmethod
def __prepare__(*args, **kwargs):
return ODict()
class Bar(metaclass=Base):
"""
>>> Bar._order
['__module__', '__doc__', 'bar']
"""
@property
def bar(self):
return 0
"""
>>> a = A() class A(object):
>>> a.f() """
[2, 1] >>> a = A()
>>> a.g() >>> a.f()
(False, True) [2, 1]
>>> del_item({1: 'a', 2: 'b'}, 1) >>> a.g()
{2: 'b'} (False, True)
>>> del_item(list(range(10)), 2) """
[0, 1, 3, 4, 5, 6, 7, 8, 9]
>>> del_dict({1: 'a', 2: 'b'}, 1)
{2: 'b'}
>>> del_list(list(range(5)), 3)
[0, 1, 2, 4]
>>> del_int(list(range(5)), 3)
[0, 1, 2, 4]
>>> del_list_int(list(range(5)), 3)
[0, 1, 2, 4]
>>> del_int({-1: 'neg', 1: 'pos'}, -1)
{1: 'pos'}
"""
class A:
def f(self): def f(self):
self.refs = [3,2,1] self.refs = [3,2,1]
del self.refs[0] del self.refs[0]
...@@ -33,21 +18,65 @@ class A: ...@@ -33,21 +18,65 @@ class A:
return (hasattr(self, u"a"), hasattr(self, u"g")) return (hasattr(self, u"a"), hasattr(self, u"g"))
def del_item(L, o): def del_item(L, o):
"""
>>> del_item({1: 'a', 2: 'b'}, 1)
{2: 'b'}
>>> del_item(list(range(10)), 2)
[0, 1, 3, 4, 5, 6, 7, 8, 9]
"""
del L[o] del L[o]
return L return L
def del_dict(dict D, o): def del_dict(dict D, o):
"""
>>> del_dict({1: 'a', 2: 'b'}, 1)
{2: 'b'}
"""
del D[o] del D[o]
return D return D
def del_list(list L, o): def del_list(list L, o):
"""
>>> del_list(list(range(5)), 3)
[0, 1, 2, 4]
"""
del L[o] del L[o]
return L return L
def del_int(L, int i): def del_int(L, int i):
"""
>>> del_int(list(range(5)), 3)
[0, 1, 2, 4]
>>> del_int({-1: 'neg', 1: 'pos'}, -1)
{1: 'pos'}
"""
del L[i] del L[i]
return L return L
def del_list_int(L, int i): def del_list_int(L, int i):
"""
>>> del_list_int(list(range(5)), 3)
[0, 1, 2, 4]
"""
del L[i] del L[i]
return L return L
def del_temp_slice(a):
"""
>>> class A(object):
... attr = [1,2,3]
>>> a = A()
>>> a.attr
[1, 2, 3]
>>> del_temp_slice(a)
[]
>>> a.attr
[]
>>> del_temp_slice(a)
[]
>>> a.attr
[]
"""
while a.attr:
del a.attr[:]
return a.attr
...@@ -48,6 +48,11 @@ def test_optimised(): ...@@ -48,6 +48,11 @@ def test_optimised():
assert isinstance(complex(), complex) assert isinstance(complex(), complex)
assert not isinstance(u"foo", int) assert not isinstance(u"foo", int)
assert isinstance(A, type) assert isinstance(A, type)
assert isinstance(A(), A)
cdef type typed_type = A
assert isinstance(A(), typed_type)
cdef object untyped_type = A
assert isinstance(A(), <type>untyped_type)
return True return True
@cython.test_assert_path_exists('//PythonCapiCallNode') @cython.test_assert_path_exists('//PythonCapiCallNode')
...@@ -59,13 +64,11 @@ def test_optimised_tuple(): ...@@ -59,13 +64,11 @@ def test_optimised_tuple():
>>> test_optimised_tuple() >>> test_optimised_tuple()
True True
""" """
assert isinstance(int(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice)) assert isinstance(int(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, A))
assert isinstance(list(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice)) assert isinstance(list(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, A))
assert isinstance(A(), (int, long, float, bytes, str, unicode, tuple, list, dict, set, slice, A))
return True return True
@cython.test_assert_path_exists('//SimpleCallNode//SimpleCallNode')
@cython.test_fail_if_path_exists('//SimpleCallNode//PythonCapiCallNode',
'//PythonCapiCallNode//SimpleCallNode')
def test_custom(): def test_custom():
""" """
>>> test_custom() >>> test_custom()
......
cdef class Owner:
cdef object x
cdef call_me_with_owner(Owner owner, x):
owner.x = "def" # overwrite external reference
return x # crashes if x is not owned by function or caller
def test_ext_type_attr():
"""
>>> test_ext_type_attr()
'abc5'
"""
owner = Owner()
owner.x = ''.join("abc%d" % 5) # non-interned object
return call_me_with_owner(owner, owner.x)
cdef void call_me_without_gil(Owner owner, x) with gil:
owner.x = "def" # overwrite external reference
print x # crashes if x is not owned by function or caller
def test_ext_type_attr_nogil():
"""
>>> test_ext_type_attr_nogil()
abc5
"""
owner = Owner()
owner.x = ''.join("abc%d" % 5) # non-interned object
with nogil:
call_me_without_gil(owner, owner.x)
# the following isn't dangerous as long as index access uses temps
cdef call_me_with_list(list l, x):
l[:] = [(1,2), (3,4)] # overwrite external reference
return x # crashes if x is not owned by function or caller
def test_index():
"""
>>> test_index()
[3, 4]
"""
l = [[1,2],[3,4]]
return call_me_with_list(l, l[1])
...@@ -25,7 +25,7 @@ def simple(): ...@@ -25,7 +25,7 @@ def simple():
xptrptr = &xptr xptrptr = &xptr
assert typeof(xptrptr) == "double **", typeof(xptrptr) assert typeof(xptrptr) == "double **", typeof(xptrptr)
b = b"abc" b = b"abc"
assert typeof(b) == "char *", typeof(b) assert typeof(b) == "bytes object", typeof(b)
s = "abc" s = "abc"
assert typeof(s) == "str object", typeof(s) assert typeof(s) == "str object", typeof(s)
u = u"xyz" u = u"xyz"
...@@ -57,7 +57,7 @@ def slicing(): ...@@ -57,7 +57,7 @@ def slicing():
>>> slicing() >>> slicing()
""" """
b = b"abc" b = b"abc"
assert typeof(b) == "char *", typeof(b) assert typeof(b) == "bytes object", typeof(b)
b1 = b[1:2] b1 = b[1:2]
assert typeof(b1) == "bytes object", typeof(b1) assert typeof(b1) == "bytes object", typeof(b1)
b2 = b[1:2:2] b2 = b[1:2:2]
...@@ -92,9 +92,9 @@ def indexing(): ...@@ -92,9 +92,9 @@ def indexing():
>>> indexing() >>> indexing()
""" """
b = b"abc" b = b"abc"
assert typeof(b) == "char *", typeof(b) assert typeof(b) == "bytes object", typeof(b)
b1 = b[1] b1 = b[1]
assert typeof(b1) == "char", typeof(b1) # FIXME: Python object ?? assert typeof(b1) == "Python object", typeof(b1)
u = u"xyz" u = u"xyz"
assert typeof(u) == "unicode object", typeof(u) assert typeof(u) == "unicode object", typeof(u)
u1 = u[1] u1 = u[1]
...@@ -479,3 +479,10 @@ def large_literals(): ...@@ -479,3 +479,10 @@ def large_literals():
c, d = 10, 100000000000000000000000000000000 c, d = 10, 100000000000000000000000000000000
assert typeof(c) == "long", typeof(c) assert typeof(c) == "long", typeof(c)
assert typeof(d) == "Python object", typeof(d) assert typeof(d) == "Python object", typeof(d)
# Regression test for trac #638.
def bar(foo):
qux = foo
quux = foo[qux.baz]
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