Cythonのどツボり方シリーズ(2)

Empty declarator と Syntax error in C variable declaration の合わせ業。

pkg/abc.pxd
1 cdef class Abc(object):
2     cpdef readonly int IF
pkg/abc.pyx
1 cdef class Abc(object):
2     def __cinit__(self):
3         self.IF = 0
setup.py
 1 from distutils.core import setup
 2 from distutils.extension import Extension
 3 from Cython.Distutils import build_ext
 4  
 5 setup(
 6     cmdclass={'build_ext': build_ext},
 7     packages=['pkg'],
 8     package_dir = {'pkg': 'pkg'},
 9     ext_modules=[
10         Extension("pkg.abc",
11                   [
12                 "pkg/abc.pxd",
13                 "pkg/abc.pyx",
14                 ]),
15         ]
16 )

__init__.pyはいるとする。今度は

これをビルドしようとするとこうなる(0.22の情報ですよ):

 1 me@host: mypkg$ python setup.py build_ext --inplace
 2 running build_ext
 3 cythoning pkg/abc.pyx to pkg\abc.c
 4 
 5 Error compiling Cython file:
 6 ------------------------------------------------------------
 7 ...
 8 cdef class Abc(object):
 9     cpdef readonly int IF
10                       ^
11 ------------------------------------------------------------
12 
13 pkg\abc.pxd:2:23: Empty declarator
14 
15 Error compiling Cython file:
16 ------------------------------------------------------------
17 ...
18 cdef class Abc(object):
19     cpdef readonly int IF
20                       ^
21 ------------------------------------------------------------
22 
23 pkg\abc.pxd:2:23: Syntax error in C variable declaration
24 
25 Error compiling Cython file:
26 ------------------------------------------------------------
27 ...
28 cdef class Abc(object):
29     def __cinit__(self):
30         self.IF = 0
31             ^
32 ------------------------------------------------------------
33 
34 pkg\abc.pyx:3:13: Expected an identifier
35 building 'pkg.abc' extension
36 C:\Users\hhsprings\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -Ic:\Python27\include -Ic:\Python27\PC
37  /Tcpkg\abc.c /Fobuild\temp.win-amd64-2.7\Release\pkg\abc.obj
38 abc.c
39 pkg\abc.c(1) : fatal error C1189: #error :  Do not use this file, it is the result of a failed Cython compilation.
40 error: command 'C:\\Users\\hhsprings\\AppData\\Local\\Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\VC\\Bin\\amd64\\cl.exe' failed with exit status 2
41 me@host: mypkg$

今回のこれは正直気づきにくい。こうするとビルド出来る:

pkg/abc.pxd
1 cdef class Abc(object):
2     cpdef readonly int IF_
pkg/abc.pyx
1 cdef class Abc(object):
2     def __cinit__(self):
3         self.IF_ = 0

pure Python では:

 1 >>> if = 10
 2   File "<stdin>", line 1
 3     if = 10
 4        ^
 5 SyntaxError: invalid syntax
 6 >>> IF = 10
 7 >>> 
 8 >>> while = 20
 9   File "<stdin>", line 1
10     while = 20
11           ^
12 SyntaxError: invalid syntax
13 >>> WHILE = 20
14 >>> 

ので、IF は cython ではキーワード扱いなのだろうか? python のキーワードリストは keyword モジュールから得られる:

 1 >>> import keyword
 2 >>> import string
 3 >>> print("\n".join(map(string.upper, keyword.kwlist)))
 4 AND
 5 AS
 6 ASSERT
 7 BREAK
 8 CLASS
 9 CONTINUE
10 DEF
11 DEL
12 ELIF
13 ELSE
14 EXCEPT
15 EXEC
16 FINALLY
17 FOR
18 FROM
19 GLOBAL
20 IF
21 IMPORT
22 IN
23 IS
24 LAMBDA
25 NOT
26 OR
27 PASS
28 PRINT
29 RAISE
30 RETURN
31 TRY
32 WHILE
33 WITH
34 YIELD
35 >>> 

ので、こんな検証プログラムを書いてみる:

実験用 setup.py
 1 import string, keyword, os
 2 for x in map(string.upper, keyword.kwlist):
 3     open("pkg/abc.pxd", "wb").write("""\
 4 cdef class Abc(object):
 5     cpdef readonly int {}
 6 """.format(x))
 7     open("pkg/abc.pyx", "wb").write("""\
 8 cdef class Abc(object):
 9     def __cinit__(self):
10         self.{} = 0
11 """.format(x))
12 
13     if os.path.exists("pkg/abc.c"):
14         os.remove("pkg/abc.c")
15     if os.path.exists("pkg/abc.pyd"):
16         os.remove("pkg/abc.pyd")
17 
18     from distutils.core import setup
19     from distutils.extension import Extension
20     from Cython.Distutils import build_ext
21     try:
22         setup(
23             cmdclass={'build_ext': build_ext},
24             packages=['pkg'],
25             package_dir = {'pkg': 'pkg'},
26             ext_modules=[
27                 Extension("pkg.abc",
28                           [
29                         "pkg/abc.pxd",
30                         "pkg/abc.pyx",
31                         ]),
32                 ]
33             )
34     except:
35         pass

これらが NG:

1     cpdef readonly int DEF
2                       ^
3     cpdef readonly int ELIF
4                       ^
5     cpdef readonly int ELSE
6                       ^
7     cpdef readonly int IF
8                       ^

なんだろうなぁこれ。C/C++ のキーワードというわけでもないしな…。