Commit b712ad56 authored by Robert Bradshaw's avatar Robert Bradshaw

merge cython-devel

parents be696078 159a0108
...@@ -38,6 +38,7 @@ Options: ...@@ -38,6 +38,7 @@ Options:
-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.
--directive <name>=<value>[,<name=value,...] Overrides a compiler directive --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
""" """
...@@ -89,6 +90,8 @@ def parse_command_line(args): ...@@ -89,6 +90,8 @@ def parse_command_line(args):
options.obj_only = 0 options.obj_only = 0
elif option in ("-+", "--cplus"): elif option in ("-+", "--cplus"):
options.cplus = 1 options.cplus = 1
elif option == "--embed":
Options.embed = True
elif option.startswith("-I"): elif option.startswith("-I"):
options.include_path.append(get_param(option)) options.include_path.append(get_param(option))
elif option == "--include-dir": elif option == "--include-dir":
......
...@@ -1642,6 +1642,7 @@ class IndexNode(ExprNode): ...@@ -1642,6 +1642,7 @@ class IndexNode(ExprNode):
error(self.pos, error(self.pos,
"Invalid index type '%s'" % "Invalid index type '%s'" %
self.index.type) self.index.type)
self.gil_check(env)
def gil_check(self, env): def gil_check(self, env):
if not self.is_buffer_access: if not self.is_buffer_access:
...@@ -1650,6 +1651,17 @@ class IndexNode(ExprNode): ...@@ -1650,6 +1651,17 @@ class IndexNode(ExprNode):
gil_message = "Indexing Python object" gil_message = "Indexing Python object"
def gil_check(self, env):
if self.is_buffer_access and env.nogil:
if env.directives['boundscheck']:
error(self.pos, "Cannot check buffer index bounds without gil; use boundscheck(False) directive")
return
elif self.type.is_pyobject:
error(self.pos, "Cannot access buffer with object dtype without gil")
return
super(IndexNode, self).gil_check(env)
def check_const_addr(self): def check_const_addr(self):
self.base.check_const_addr() self.base.check_const_addr()
self.index.check_const() self.index.check_const()
...@@ -1741,14 +1753,13 @@ class IndexNode(ExprNode): ...@@ -1741,14 +1753,13 @@ class IndexNode(ExprNode):
index_code = self.index.py_result() index_code = self.index.py_result()
if self.base.type is dict_type: if self.base.type is dict_type:
function = "PyDict_SetItem" function = "PyDict_SetItem"
elif self.base.type is list_type: # It would seem that we could specalized lists/tuples, but that
function = "PyList_SetItem" # shouldn't happen here.
# don't use PyTuple_SetItem(), as we'd normally get a # Both PyList_SetItem PyTuple_SetItem and a Py_ssize_t as input,
# TypeError when changing a tuple, while PyTuple_SetItem() # not a PyObject*, and bad conversion here would give the wrong
# would allow updates # exception. Also, tuples are supposed to be immutable, and raise
# # TypeErrors when trying to set their entries (PyTuple_SetItem
#elif self.base.type is tuple_type: # is for creating new tuples from).
# function = "PyTuple_SetItem"
else: else:
function = "PyObject_SetItem" function = "PyObject_SetItem"
code.putln( code.putln(
...@@ -5786,12 +5797,11 @@ static int __Pyx_cdivision_warning(void) { ...@@ -5786,12 +5797,11 @@ static int __Pyx_cdivision_warning(void) {
"division with oppositely signed operands, C and Python semantics differ", "division with oppositely signed operands, C and Python semantics differ",
%(FILENAME)s, %(FILENAME)s,
%(LINENO)s, %(LINENO)s,
%(MODULENAME)s, __Pyx_MODULE_NAME,
NULL); NULL);
} }
""" % { """ % {
'FILENAME': Naming.filename_cname, 'FILENAME': Naming.filename_cname,
'MODULENAME': Naming.modulename_cname,
'LINENO': Naming.lineno_cname, 'LINENO': Naming.lineno_cname,
}) })
......
...@@ -55,6 +55,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -55,6 +55,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
else: else:
env.doc = self.doc env.doc = self.doc
env.directives = self.directives env.directives = self.directives
if Options.embed:
self.__main__cname = env.intern_identifier(EncodedString("__main__"))
self.body.analyse_declarations(env) self.body.analyse_declarations(env)
def process_implementation(self, options, result): def process_implementation(self, options, result):
...@@ -249,7 +251,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -249,7 +251,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.globalstate.use_utility_code(refcount_utility_code) code.globalstate.use_utility_code(refcount_utility_code)
code.putln('const char *%s = "%s";' % (Naming.modulename_cname, self.full_module_name)) code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) code.putln("/* Implementation of %s */" % env.qualified_name)
...@@ -267,6 +269,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -267,6 +269,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_module_init_func(modules[:-1], env, code) self.generate_module_init_func(modules[:-1], env, code)
code.mark_pos(None) code.mark_pos(None)
self.generate_module_cleanup_func(env, code) self.generate_module_cleanup_func(env, code)
if Options.embed:
self.generate_main_method(env, code)
self.generate_filename_table(code) self.generate_filename_table(code)
self.generate_utility_functions(env, code, h_code) self.generate_utility_functions(env, code, h_code)
...@@ -1723,6 +1727,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1723,6 +1727,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("Py_INCREF(Py_None); return Py_None;") code.putln("Py_INCREF(Py_None); return Py_None;")
code.putln('}') code.putln('}')
def generate_main_method(self, env, code):
code.globalstate.use_utility_code(main_method.specialize(module_name=env.module_name))
def generate_filename_init_call(self, code): def generate_filename_init_call(self, code):
code.putln("%s();" % Naming.fileinit_cname) code.putln("%s();" % Naming.fileinit_cname)
...@@ -1787,6 +1794,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1787,6 +1794,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
env.module_cname, env.module_cname,
Naming.builtins_cname, Naming.builtins_cname,
code.error_goto(self.pos))) code.error_goto(self.pos)))
if Options.embed:
code.putln(
'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % (
env.module_cname,
self.__main__cname,
code.error_goto(self.pos)))
if Options.pre_import is not None: if Options.pre_import is not None:
code.putln( code.putln(
'%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % ( '%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % (
...@@ -2431,3 +2444,27 @@ static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL; ...@@ -2431,3 +2444,27 @@ static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL;
#define __Pyx_XGIVEREF(r) if((r) == NULL) ; else __Pyx_GIVEREF(r) #define __Pyx_XGIVEREF(r) if((r) == NULL) ; else __Pyx_GIVEREF(r)
#define __Pyx_XGOTREF(r) if((r) == NULL) ; else __Pyx_GOTREF(r) #define __Pyx_XGOTREF(r) if((r) == NULL) ; else __Pyx_GOTREF(r)
""") """)
main_method = UtilityCode(
impl = """
int main(int argc, char** argv) {
int r = 0;
PyObject* m = NULL;
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
#if PY_MAJOR_VERSION < 3
init%(module_name)s();
#else
m = PyInit_%(module_name)s(name);
#endif
if (PyErr_Occurred() != NULL) {
r = 1;
PyErr_Print(); /* This exits with the right code if SystemExit. */
if (Py_FlushLine()) PyErr_Clear();
}
Py_XDECREF(m);
Py_Finalize();
return r;
}
""")
...@@ -53,6 +53,11 @@ optimize_simple_methods = 1 ...@@ -53,6 +53,11 @@ optimize_simple_methods = 1
# Append the c file and line number to the traceback for exceptions. # Append the c file and line number to the traceback for exceptions.
c_line_in_traceback = 1 c_line_in_traceback = 1
# Whether or not to embed the Python interpreter, for use in making a
# standalone executable. This will provide a main() method which simply
# executes the body of this module.
embed = False
# Declare pragmas # Declare pragmas
option_defaults = { option_defaults = {
......
PYVERSION = 2.2 # Makefile for creating our standalone Cython program
PYHOME = $(HOME)/pkg/python/$(PYVERSION) PYVERSION=2.3
PYARCH = $(PYHOME)/$(ARCH) PYPREFIX=/usr
PYINCLUDE = \ INCLUDES=-I$(PYPREFIX)/include/python$(PYVERSION)
-I$(PYHOME)/include/python$(PYVERSION) \
-I$(PYARCH)/include/python$(PYVERSION)
PYLIB = -L$(PYARCH)/lib/python$(PYVERSION)/config \
-lpython$(PYVERSION) \
-ldl -lpthread -lutil -lm
%.c: %.pyx embedded: embedded.o
../../bin/cython $< gcc -o $@ $^ -lpython$(PYVERSION)
%.o: %.c embedded.o: embedded.c
gcc -c -fPIC $(PYINCLUDE) $< gcc -c $^ $(INCLUDES)
#%.so: %.o embedded.c: embedded.pyx
# gcc -shared $< -lm -o $@ @python ../../cython.py --embed embedded.pyx
all: main all: embedded
main: main.o embedded.o
gcc main.o embedded.o $(PYLIB) -o main
clean: clean:
@echo Cleaning Demos/embed @echo Cleaning Demos/embed
@rm -f *~ *.o *.so core core.* embedded.h embedded.c main @rm -f *~ *.o *.so core core.* *.c embedded
embedded.h: embedded.c
main.o: embedded.h
PYVERSION = 2.2 # Makefile for creating our standalone Cython program
PYHOME = $(HOME)/pkg/python/$(PYVERSION) PYVERSION=2.3
PYARCH = $(PYHOME)/$(ARCH) PYPREFIX=/usr
PYINCLUDE = \ INCLUDES=-I$(PYPREFIX)/include/python$(PYVERSION)
-I$(PYHOME)/include/python$(PYVERSION) \
-I$(PYARCH)/include/python$(PYVERSION)
PYLIB = -L$(PYARCH)/lib/python$(PYVERSION)/config \
-lpython$(PYVERSION) \
-ldl -lpthread -lutil -lm
%.c: %.pyx embedded: embedded.o
../../bin/cython $< gcc -o $@ $^ -lpython$(PYVERSION)
%.o: %.c embedded.o: embedded.c
gcc -c -fPIC $(PYINCLUDE) $< gcc -c $^ $(INCLUDES)
#%.so: %.o embedded.c: embedded.pyx
# gcc -shared $< -lm -o $@ @python ../../cython.py --embed embedded.pyx
all: main all: embedded
main: main.o embedded.o
gcc main.o embedded.o $(PYLIB) -o main
clean: clean:
@echo Cleaning Demos/embed @echo Cleaning Demos/embed
@rm -f *~ *.o *.so core core.* embedded.h embedded.c main @rm -f *~ *.o *.so core core.* *.c embedded
embedded.h: embedded.c
main.o: embedded.h
cdef public void spam():
praise()
def praise(): print __name__
print "Spam, glorious spam!"
if __name__ == "__main__":
print "Hi, I'm embedded."
else:
print "I'm being imported."
Pyrex - Installation Instructions Cython - Installation Instructions
================================= ==================================
You have two installation options: You have two installation options:
...@@ -8,7 +8,7 @@ You have two installation options: ...@@ -8,7 +8,7 @@ You have two installation options:
python setup.py install python setup.py install
This will install the Pyrex package This will install the Cython package
into your Python system. into your Python system.
OR OR
......
...@@ -14,4 +14,3 @@ large_consts_T237 ...@@ -14,4 +14,3 @@ large_consts_T237
bad_c_struct_T252 bad_c_struct_T252
missing_baseclass_in_predecl_T262 missing_baseclass_in_predecl_T262
ifelseexpr_T267 ifelseexpr_T267
cdef_setitem_T284
cimport e_bufaccess_pxd # was needed to provoke a bug involving ErrorType cimport e_bufaccess_pxd # was needed to provoke a bug involving ErrorType
import cython
def f(): def f():
cdef object[e_bufaccess_pxd.T] buf cdef object[e_bufaccess_pxd.T] buf
def withnogil_access_fail():
cdef object[int] buf = None
with nogil:
buf[2] = 2
@cython.boundscheck(False)
def withnogil_access_ok():
cdef object[int] buf = None
with nogil:
buf[2] = 2 # No error should be triggered here
@cython.boundscheck(False)
def withnogil_access_fail_2():
cdef object[object] buf = None
with nogil:
buf[2] = 2 # Not OK as dtype is object
def withnogil_acquire(x):
cdef object[int] buf
with nogil:
buf = x
_ERRORS = u""" _ERRORS = u"""
3:9: 'nothing' is not a type identifier 3:9: 'nothing' is not a type identifier
10:11: Cannot check buffer index bounds without gil; use boundscheck(False) directive
22:11: Cannot access buffer with object dtype without gil
22:11: Assignment of Python object not allowed without gil
27:12: Assignment of Python object not allowed without gil
""" """
...@@ -1449,3 +1449,18 @@ def complex_struct_inplace(object[LongComplex] buf): ...@@ -1449,3 +1449,18 @@ def complex_struct_inplace(object[LongComplex] buf):
buf[0].imag += 2 buf[0].imag += 2
print buf[0].real, buf[0].imag print buf[0].real, buf[0].imag
#
# Nogil
#
@testcase
@cython.boundscheck(False)
def buffer_nogil():
"""
>>> buffer_nogil()
10
"""
cdef object[int] buf = IntMockBuffer(None, [1,2,3])
with nogil:
buf[1] = 10
return buf[1]
__doc__ = u''' __doc__ = u'''
>>> no_cdef() >>> no_cdef()
>>> with_cdef() >>> with_cdef()
>>> test_list(range(11), -2, None)
[0, 1, 2, 3, 4, 5, 6, 7, 8, None, 10]
>>> test_list(range(11), "invalid index", None)
Traceback (most recent call last):
...
TypeError: list indices must be integers
''' '''
def no_cdef(): def no_cdef():
lst = range(11) lst = range(11)
...@@ -15,3 +21,7 @@ def with_cdef(): ...@@ -15,3 +21,7 @@ def with_cdef():
lst[ob] = -10 lst[ob] = -10
cdef dict dd = {} cdef dict dd = {}
dd[ob] = -10 dd[ob] = -10
def test_list(list L, object i, object a):
L[i] = a
return L
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