Coverage for src/ensae_teaching_cs/faq/faq_cython.py: 58%
38 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-04-28 06:23 +0200
« prev ^ index » next coverage.py v7.1.0, created at 2023-04-28 06:23 +0200
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Cython helpers
6"""
8import os
9import sys
10import warnings
12from pyquickhelper.loghelper import run_cmd, noLOG
15class CustomCythonError(Exception):
16 """
17 raised by function @see fn compile_cython_single_script
18 when a script cannot be compiled with Cython
19 """
20 pass
23def compile_cython_single_script(script, skip_warn=True, fLOG=noLOG):
24 """
25 This function considers a script ``.pyx``, writes
26 the proper setup file, and compiles it.
28 :param script: filename
29 :param skip_warn: skip warnings
30 :param fLOG: logging function
31 :return: output
33 The function applies the steps described in the basic tutorial
34 :epkg:`The Basics of Cython`.
35 The function creates a ``setup.py``
36 in the same location and compiles it.
38 The compilation requires a compiler
39 (not `MinGW <http://www.mingw.org/>`_ or
40 `Visual Studio (Community Edition) <https://www.microsoft.com/france/visual-studio/produits/community/Default.aspx>`_).
41 If none was found, Python usually displays an error message like::
43 Unable to find vcvarsall.bat
45 You can also read this old blog post:
46 `Build a Python 64 bit extension on Windows <http://www.xavierdupre.fr/blog/2013-07-07_nojs.html>`_
47 about this file:: ``C:\\Python35_x64\\lib\\distutils\\msvc9compiler.py``.
49 .. faqref::
50 :tag: cython
51 :title: Compiler une function Cython ?
53 Cette fonction compile un script
54 `Cython <http://cython.org/>`_.
55 Cette extension permet d'implémenter des fonctions Python dans un
56 pseudo-langage proche du `C <https://en.wikipedia.org/wiki/C_(programming_language)>`_.
57 Il faut suivre les instructions décrite dans le tutorial
58 :epkg:`The Basics of Cython`
59 pour réussir à utiliser une fonction codée en Cython.
60 C'est ce que fait la fonction :func:`compile_cython_single_script`.
62 Etant donné que la partie en pseudo C est compilée afin de la rendre beaucoup
63 plus rapide, la partie la plus difficile est généralement celle qui consiste à faire
64 en sorte que l'interpréteur Python trouve le <b>bon</b> compilateur.
65 Ce compilateur est nécessairement le même que celui utilisé pour compiler
66 Python et celui-ci change à chaque version.
67 Voir
68 `Compiling Python on Windows <https://docs.python.org/3/using/windows.html?highlight=visual%20studio#compiling-python-on-windows>`_
69 et faire attention à la version de Python que vous utilisez.
70 """
71 ext = os.path.splitext(script)[-1]
72 if ext != ".pyx":
73 raise ValueError("no extension .pyx: " + script)
74 if not os.path.exists(script):
75 raise FileNotFoundError(script)
77 name = os.path.split(script)[-1]
78 namen = os.path.splitext(name)[0]
79 setup_script = """
80 from setuptools import setup
81 from Cython.Build import cythonize
82 setup(
83 name='{1}',
84 ext_modules=cythonize("{0}",
85 compiler_directives={{'language_level': {2}}})
86 )
87 """.replace(" ", "").format(name, namen, sys.version_info[0])
89 current, name = os.path.split(script)
90 filename = os.path.join(os.path.dirname(script), name + ".setup.py")
91 with open(filename, "w") as f:
92 f.write(setup_script)
94 cmd = sys.executable + f" -u {filename} build_ext --inplace"
96 out, err = run_cmd(cmd, wait=True, fLOG=fLOG, change_path=current)
97 if len(err) > 0:
98 if skip_warn:
99 do_raise = False
100 lines = err.split("\n")
101 for line in lines:
102 if len(line) > 0 and not line.startswith(" "):
103 if "UserWarning" not in line:
104 do_raise = True
105 break
106 else:
107 do_raise = True
108 if do_raise:
109 with open(script, "r", encoding="utf-8") as f:
110 content = f.read()
111 raise CustomCythonError(
112 f"CMD:\n{cmd}\nOUT:\n{out}ERR:\n{err}\nSCRIPT:\n{content}")
113 else:
114 warnings.warn(
115 f"[compile_cython_single_script] CMD:\n{cmd}\nOUT:\n{out}ERR:\n{err}")
116 return out