Problem 1
In my previous post I mentioned that, “After memorizing a few common errors and dealing with them, the whole process is not really that bad”. This is true, and I see no reason why I can’t try to help with the learning process. I apologize in advance for some of the poor formatting; the WordPress publishing software absolutely slaughtered most of my word processor’s formatting and made reformatting it painful.
In chess, one way to think of a queen piece is as a combined rook and bishop. So, the way I implemented figuring moves and threat was to leverage my already written rook and bishop implementations by calling their appropriate functions. One of the first problems I ran into was with visibility; let’s take a look at how I solved the problem:
Code change (in Rook.pyx):
Original:
def _rook_is_valid_move(self, point):
Change:
cdef _rook_is_valid_move(self, point):
Problem:
Traceback (most recent call last):
File “D:\Code Library\Chess\src\main.py”, line 47, in <module>
cProfile.run(‘main()’, ‘profile.txt’)
File “C:\Python26\lib\cProfile.py”, line 29, in run
prof = prof.run(statement)
File “C:\Python26\lib\cProfile.py”, line 135, in run
return self.runctx(cmd, dict, dict)
File “C:\Python26\lib\cProfile.py”, line 140, in runctx
exec cmd in globals, locals
File “<string>”, line 1, in <module>
File “D:\Code Library\Chess\src\main.py”, line 44, in main
game_controller.main_loop()
File “D:\Code Library\Chess\src\game\game_controller.py”, line 94, in main_loop
handle_event(event)
File “D:\Code Library\Chess\src\game\game_controller.py”, line 125, in handle_event
handle_rightclick(event)
File “D:\Code Library\Chess\src\game\game_controller.py”, line 145, in handle_rightclick
handle_move(selected, boardpoint, cur_player)
File “D:\Code Library\Chess\src\game\game_controller.py”, line 150, in handle_move
if selected.is_valid_move(boardpoint):
File “queen.pyx”, line 50, in pieces.queen.Queen.is_valid_move (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\queen.c:713)
AttributeError: ‘module’ object has no attribute ‘_rook_is_valid_move’
Cython can’t find our newly Cython’d function. This is might be due to the fact that we haven’t cimported rook, only imported the Python version. Let’s cimport rook in queen.pyx. Alas, that does not quite fix the problem.
Problem:
Error converting Pyrex file to C:
————————————————————
…
@author: Brett Geren
”’
import piece
import bishop
cimport rook
^
————————————————————
D:\Code Library\Chess\src\pieces\queen.pyx:39:8: ‘rook.pxd’ not found
Cython can’t find rook even though it exists. If we look at the last line, we’ll see it’s because Cython is searching for a file that does not exist, the rook definition file. Cython functions (and class/extension attributes) are not externally visible by default; you can make them visible by defining them in a definition file (a C/C++ style header) [talked about here]. Let’s create a definition file that defines the function (named rook.pxd):
New Problem:
Traceback (most recent call last):
File “D:\Code Library\Chess\src\main.py”, line 41, in <module>
from game import game_controller
File “D:\Code Library\Chess\src\game\game_controller.py”, line 43, in <module>
import game_view
File “D:\Code Library\Chess\src\game\game_view.py”, line 42, in <module>
from model import game_model
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 328, in load_module
self.pyxbuild_dir)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 181, in load_module
mod = imp.load_dynamic(name, so_path)
File “game_model.pyx”, line 37, in init model.game_model (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\game_model.c:2212)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 328, in load_module
self.pyxbuild_dir)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 181, in load_module
mod = imp.load_dynamic(name, so_path)
File “player.pyx”, line 39, in init model.player (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\player.c:3226)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 328, in load_module
self.pyxbuild_dir)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 181, in load_module
mod = imp.load_dynamic(name, so_path)
File “queen.pyx”, line 1, in init pieces.queen (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\queen.c:1363)
ImportError: Building module failed: ['ImportError: Building module failed: [\'ImportError: Building module failed: ["AttributeError: \\\'module\\\' object has no attribute \\\'__pyx_capi__\\\'\\\\n"]\\n\’]\n’]
This error is extremely unhelpful; to make matters worse, if you try and Google the problem you get nothing substantive. As awkward as this may seem, I found that the solution to this and several other “odd” problems was to simply force a recompile of the entire project by cleaning (deleting) the generated and compiled code. The location of the generated code can be found in several places in the traceback; mine is C:\Users\Babyface/.pyxbld.
Problem 2
The following illustrates a possible problem you may encounter if you try making Cython functions externally visible:
Error converting Pyrex file to C:
————————————————————
…
delta_diff = math.fabs(col_diff – row_diff)
return (delta_diff != 0 and (col_diff == 0 or row_diff == 0)
and __path_is_clear(self, point, col_diff == 0))
cdef _rook_get_possible_moves(self, list):
^
————————————————————
D:\Code Library\Chess\src\pieces\rook.pyx:81:5: Function signature does not match previous declaration
The implementation in rook.pyx:
cdef _rook_get_possible_moves(self, list)
The declaration in rook.pxd:
cdef _rook_get_possible_moves(self, list)
As the above code selections show, the function signatures sure look the same. That may be easy for an intelligent human to decipher, but what about an “unintelligent” compiler blindly following instructions? Cython can figure out what self is (since it is, in a way, pre-typed). It obviously realizes that the functions both have the same names; otherwise, we wouldn’t be getting such a specific error. This can only mean that Cython has some issue with the list argument. The list argument is a Python list and herein lays the problem; Cython thinks that the two lists have two different types. I’m not sure where I read this (I believe it was in a mailing list repo for a project that utilizes Cython), but several of the developers there were under the impression that Cython can sometimes generates several C structs and types for the same Python types if it ends up getting imported multiple times in different files. This would certainly lead to the compiler believing that the lists were of different types. The easiest way to fix this problem is to explicitly statically type list; however, list isn’t a simple C-type that we can statically type…… Thankfully, there exists a generic “object” type that I believe you can use for all Python objects. This fixes the problem:
cdef _rook_get_possible_moves(self, object list)
Problem 3
Another problem that you could face looks deceptively like the above problem:
Traceback (most recent call last):
File “D:\Code Library\Chess\src\main.py”, line 41, in <module>
from game import game_controller
File “D:\Code Library\Chess\src\game\game_controller.py”, line 43, in <module>
import game_view
File “D:\Code Library\Chess\src\game\game_view.py”, line 42, in <module>
from model import game_model
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 328, in load_module
self.pyxbuild_dir)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 181, in load_module
mod = imp.load_dynamic(name, so_path)
File “game_model.pyx”, line 37, in init model.game_model (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\game_model.c:2212)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 328, in load_module
self.pyxbuild_dir)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 181, in load_module
mod = imp.load_dynamic(name, so_path)
File “player.pyx”, line 39, in init model.player (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\player.c:3226)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 328, in load_module
self.pyxbuild_dir)
File “C:\Python26\Lib\site-packages\pyximport\pyximport.py”, line 181, in load_module
mod = imp.load_dynamic(name, so_path)
File “queen.pyx”, line 1, in init pieces.queen (C:\Users\Babyface/.pyxbld\temp.win32-2.6\Release\pyrex\queen.c:1267)
ImportError: Building module failed: ['ImportError: Building module failed: ["ImportError: Building module failed: [\'TypeError: C function pieces.bishop._bishop_get_possible_moves has wrong signature (expected int (PyObject *, PyObject *), got PyObject *(PyObject *, PyObject *))\\\\n\']\\n”]\n’]
While this looks like another issue of the compiler incorrectly figuring types, you can see that the incorrectly figured type is the return value’s type. I found that statically typing the return value did NOT fix this issue; however, cleaning and recompiling did.
Problem 4
The next problem may be trivial, but a late night of coding ended up causing me to waste something like twenty minutes on the below:
Error converting Pyrex file to C:
————————————————————
…
#rook meets requirements
cdef int rook_col = (LEFT_ROOK_COL if
point[0] == LEFT_CASTLE_KING_POS
else RIGHT_ROOK_COL)
Rook rook = self.owner.game_model.piece_for_boardpoint((rook_col, valid_row))
^
————————————————————
D:\Code Library\Chess\src\pieces\king.pyx:129:13: Syntax error in simple statement list
The problem is that you forgot to tell the compiler that you are about to type the variable (you left out the cdef keyword).
Problem 5
The next problem sort of reiterates a lesson learned earlier:
AttributeError: ‘pieces.king.King’ object has no attribute ‘is_in_check’
Calling source code (in player.pyx):
if self.king.is_in_check(self.king.point):
ret = False
Source function in question (in king.pxd and king.pyx):
cdef is_in_check(King self, point)
Once again, the function exists but Cython can’t find it. Unlike above, the function is defined in a definition file, making it publically available to other modules. One lesson we learned earlier is that explicitly typing can solve a lot of your problems, so let’s try that here:
cdef King king = self.king
if king.is_in_check(self.king.point):
ret = False
The above will fix the issue since Cython will type king and do the correct lookup for the function. The actual issue, more than likely, was that the calling code was searching in “Python space” and it had trouble resolving the search for the function in “Cython space” (where it actually existed). Another method to fix the problem was to simply avoid OOP entirely (which is probably the source of the search issues) and explicitly call King’s is_in_check function. This will of course work since the function has been made publically available:
if King.is_in_check(self.king, self.king.point):
ret = False
Above are five problems that I personally found either frustrating to solve or common enough to make them worth writing about. Hopefully, getting over the initial Cython learning curve is slightly less painful now.








