passagemath-repl 10.4.62__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. passagemath_repl-10.4.62.data/scripts/sage-cachegrind +25 -0
  2. passagemath_repl-10.4.62.data/scripts/sage-callgrind +16 -0
  3. passagemath_repl-10.4.62.data/scripts/sage-cleaner +230 -0
  4. passagemath_repl-10.4.62.data/scripts/sage-coverage +327 -0
  5. passagemath_repl-10.4.62.data/scripts/sage-eval +14 -0
  6. passagemath_repl-10.4.62.data/scripts/sage-fixdoctests +708 -0
  7. passagemath_repl-10.4.62.data/scripts/sage-inline-fortran +12 -0
  8. passagemath_repl-10.4.62.data/scripts/sage-ipynb2rst +50 -0
  9. passagemath_repl-10.4.62.data/scripts/sage-ipython +16 -0
  10. passagemath_repl-10.4.62.data/scripts/sage-massif +25 -0
  11. passagemath_repl-10.4.62.data/scripts/sage-notebook +267 -0
  12. passagemath_repl-10.4.62.data/scripts/sage-omega +25 -0
  13. passagemath_repl-10.4.62.data/scripts/sage-preparse +302 -0
  14. passagemath_repl-10.4.62.data/scripts/sage-run +27 -0
  15. passagemath_repl-10.4.62.data/scripts/sage-run-cython +10 -0
  16. passagemath_repl-10.4.62.data/scripts/sage-runtests +9 -0
  17. passagemath_repl-10.4.62.data/scripts/sage-startuptime.py +163 -0
  18. passagemath_repl-10.4.62.data/scripts/sage-valgrind +34 -0
  19. passagemath_repl-10.4.62.dist-info/METADATA +77 -0
  20. passagemath_repl-10.4.62.dist-info/RECORD +162 -0
  21. passagemath_repl-10.4.62.dist-info/WHEEL +5 -0
  22. passagemath_repl-10.4.62.dist-info/top_level.txt +1 -0
  23. sage/all__sagemath_repl.py +119 -0
  24. sage/doctest/__init__.py +4 -0
  25. sage/doctest/__main__.py +236 -0
  26. sage/doctest/all.py +4 -0
  27. sage/doctest/check_tolerance.py +261 -0
  28. sage/doctest/control.py +1727 -0
  29. sage/doctest/external.py +534 -0
  30. sage/doctest/fixtures.py +383 -0
  31. sage/doctest/forker.py +2665 -0
  32. sage/doctest/marked_output.py +102 -0
  33. sage/doctest/parsing.py +1708 -0
  34. sage/doctest/parsing_test.py +79 -0
  35. sage/doctest/reporting.py +733 -0
  36. sage/doctest/rif_tol.py +124 -0
  37. sage/doctest/sources.py +1657 -0
  38. sage/doctest/test.py +584 -0
  39. sage/doctest/tests/1second.rst +4 -0
  40. sage/doctest/tests/99seconds.rst +4 -0
  41. sage/doctest/tests/abort.rst +5 -0
  42. sage/doctest/tests/atexit.rst +7 -0
  43. sage/doctest/tests/fail_and_die.rst +6 -0
  44. sage/doctest/tests/initial.rst +15 -0
  45. sage/doctest/tests/interrupt.rst +7 -0
  46. sage/doctest/tests/interrupt_diehard.rst +14 -0
  47. sage/doctest/tests/keyboardinterrupt.rst +11 -0
  48. sage/doctest/tests/longtime.rst +5 -0
  49. sage/doctest/tests/nodoctest +5 -0
  50. sage/doctest/tests/random_seed.rst +4 -0
  51. sage/doctest/tests/show_skipped.rst +18 -0
  52. sage/doctest/tests/sig_on.rst +9 -0
  53. sage/doctest/tests/simple_failure.rst +8 -0
  54. sage/doctest/tests/sleep_and_raise.rst +106 -0
  55. sage/doctest/tests/tolerance.rst +31 -0
  56. sage/doctest/util.py +750 -0
  57. sage/interfaces/cleaner.py +48 -0
  58. sage/interfaces/quit.py +163 -0
  59. sage/misc/all__sagemath_repl.py +51 -0
  60. sage/misc/banner.py +235 -0
  61. sage/misc/benchmark.py +221 -0
  62. sage/misc/classgraph.py +131 -0
  63. sage/misc/copying.py +22 -0
  64. sage/misc/cython.py +694 -0
  65. sage/misc/dev_tools.py +745 -0
  66. sage/misc/edit_module.py +304 -0
  67. sage/misc/explain_pickle.py +3079 -0
  68. sage/misc/gperftools.py +361 -0
  69. sage/misc/inline_fortran.py +212 -0
  70. sage/misc/messaging.py +86 -0
  71. sage/misc/pager.py +21 -0
  72. sage/misc/profiler.py +179 -0
  73. sage/misc/python.py +70 -0
  74. sage/misc/remote_file.py +53 -0
  75. sage/misc/sage_eval.py +246 -0
  76. sage/misc/sage_input.py +3621 -0
  77. sage/misc/sagedoc.py +1742 -0
  78. sage/misc/sh.py +38 -0
  79. sage/misc/trace.py +90 -0
  80. sage/repl/__init__.py +16 -0
  81. sage/repl/all.py +15 -0
  82. sage/repl/attach.py +625 -0
  83. sage/repl/configuration.py +186 -0
  84. sage/repl/display/__init__.py +1 -0
  85. sage/repl/display/fancy_repr.py +354 -0
  86. sage/repl/display/formatter.py +318 -0
  87. sage/repl/display/jsmol_iframe.py +290 -0
  88. sage/repl/display/pretty_print.py +153 -0
  89. sage/repl/display/util.py +163 -0
  90. sage/repl/image.py +302 -0
  91. sage/repl/inputhook.py +91 -0
  92. sage/repl/interface_magic.py +298 -0
  93. sage/repl/interpreter.py +854 -0
  94. sage/repl/ipython_extension.py +593 -0
  95. sage/repl/ipython_kernel/__init__.py +1 -0
  96. sage/repl/ipython_kernel/__main__.py +4 -0
  97. sage/repl/ipython_kernel/all_jupyter.py +10 -0
  98. sage/repl/ipython_kernel/install.py +301 -0
  99. sage/repl/ipython_kernel/interact.py +278 -0
  100. sage/repl/ipython_kernel/kernel.py +217 -0
  101. sage/repl/ipython_kernel/widgets.py +466 -0
  102. sage/repl/ipython_kernel/widgets_sagenb.py +587 -0
  103. sage/repl/ipython_tests.py +163 -0
  104. sage/repl/load.py +326 -0
  105. sage/repl/preparse.py +2218 -0
  106. sage/repl/prompts.py +90 -0
  107. sage/repl/rich_output/__init__.py +4 -0
  108. sage/repl/rich_output/backend_base.py +648 -0
  109. sage/repl/rich_output/backend_doctest.py +316 -0
  110. sage/repl/rich_output/backend_emacs.py +151 -0
  111. sage/repl/rich_output/backend_ipython.py +596 -0
  112. sage/repl/rich_output/buffer.py +311 -0
  113. sage/repl/rich_output/display_manager.py +829 -0
  114. sage/repl/rich_output/example.avi +0 -0
  115. sage/repl/rich_output/example.canvas3d +1 -0
  116. sage/repl/rich_output/example.dvi +0 -0
  117. sage/repl/rich_output/example.flv +0 -0
  118. sage/repl/rich_output/example.gif +0 -0
  119. sage/repl/rich_output/example.jpg +0 -0
  120. sage/repl/rich_output/example.mkv +0 -0
  121. sage/repl/rich_output/example.mov +0 -0
  122. sage/repl/rich_output/example.mp4 +0 -0
  123. sage/repl/rich_output/example.ogv +0 -0
  124. sage/repl/rich_output/example.pdf +0 -0
  125. sage/repl/rich_output/example.png +0 -0
  126. sage/repl/rich_output/example.svg +54 -0
  127. sage/repl/rich_output/example.webm +0 -0
  128. sage/repl/rich_output/example.wmv +0 -0
  129. sage/repl/rich_output/example_jmol.spt.zip +0 -0
  130. sage/repl/rich_output/example_wavefront_scene.mtl +7 -0
  131. sage/repl/rich_output/example_wavefront_scene.obj +17 -0
  132. sage/repl/rich_output/output_basic.py +391 -0
  133. sage/repl/rich_output/output_browser.py +103 -0
  134. sage/repl/rich_output/output_catalog.py +54 -0
  135. sage/repl/rich_output/output_graphics.py +320 -0
  136. sage/repl/rich_output/output_graphics3d.py +345 -0
  137. sage/repl/rich_output/output_video.py +231 -0
  138. sage/repl/rich_output/preferences.py +432 -0
  139. sage/repl/rich_output/pretty_print.py +339 -0
  140. sage/repl/rich_output/test_backend.py +201 -0
  141. sage/repl/user_globals.py +214 -0
  142. sage/tests/__init__.py +1 -0
  143. sage/tests/all.py +3 -0
  144. sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +630 -0
  145. sage/tests/arxiv_0812_2725.py +351 -0
  146. sage/tests/benchmark.py +1923 -0
  147. sage/tests/book_schilling_zabrocki_kschur_primer.py +795 -0
  148. sage/tests/book_stein_ent.py +651 -0
  149. sage/tests/book_stein_modform.py +558 -0
  150. sage/tests/cmdline.py +790 -0
  151. sage/tests/combinatorial_hopf_algebras.py +52 -0
  152. sage/tests/finite_poset.py +623 -0
  153. sage/tests/functools_partial_src.py +27 -0
  154. sage/tests/gosper-sum.py +218 -0
  155. sage/tests/lazy_imports.py +28 -0
  156. sage/tests/modular_group_cohomology.py +80 -0
  157. sage/tests/numpy.py +21 -0
  158. sage/tests/parigp.py +76 -0
  159. sage/tests/startup.py +27 -0
  160. sage/tests/symbolic-series.py +76 -0
  161. sage/tests/sympy.py +16 -0
  162. sage/tests/test_deprecation.py +31 -0
sage/misc/cython.py ADDED
@@ -0,0 +1,694 @@
1
+ # sage_setup: distribution = sagemath-repl
2
+ # sage.doctest: needs sage.misc.cython
3
+ """
4
+ Cython support functions
5
+
6
+ AUTHORS:
7
+
8
+ - William Stein (2006-01-18): initial version
9
+ - William Stein (2007-07-28): update from sagex to cython
10
+ - Martin Albrecht & William Stein (2011-08): cfile & cargs
11
+ """
12
+
13
+ # ****************************************************************************
14
+ # Copyright (C) 2006 William Stein <wstein@gmail.com>
15
+ #
16
+ # This program is free software: you can redistribute it and/or modify
17
+ # it under the terms of the GNU General Public License as published by
18
+ # the Free Software Foundation, either version 2 of the License, or
19
+ # (at your option) any later version.
20
+ # https://www.gnu.org/licenses/
21
+ # ****************************************************************************
22
+
23
+ import builtins
24
+ import os
25
+ import re
26
+ import sys
27
+ import shutil
28
+
29
+ from sage.env import (SAGE_LOCAL, cython_aliases,
30
+ sage_include_directories)
31
+ from sage.misc.temporary_file import spyx_tmp, tmp_filename
32
+ from sage.repl.user_globals import get_globals
33
+ from sage.misc.sage_ostools import restore_cwd, redirection
34
+ from sage.cpython.string import str_to_bytes
35
+ from sage.misc.cachefunc import cached_function
36
+
37
+
38
+ @cached_function
39
+ def _standard_libs_libdirs_incdirs_aliases():
40
+ r"""
41
+ Return the list of libraries and library directories.
42
+
43
+ EXAMPLES::
44
+
45
+ sage: from sage.misc.cython import _standard_libs_libdirs_incdirs_aliases
46
+ sage: _standard_libs_libdirs_incdirs_aliases()
47
+ (['mpfr', 'gmp', 'gmpxx', 'pari', ...],
48
+ [...],
49
+ [...],
50
+ {...})
51
+ """
52
+ aliases = cython_aliases()
53
+ standard_libs = [
54
+ 'mpfr', 'gmp', 'gmpxx', 'pari', 'm',
55
+ 'ec', 'gsl',
56
+ ] + aliases["CBLAS_LIBRARIES"] + [
57
+ 'ntl']
58
+ standard_libdirs = []
59
+ if SAGE_LOCAL:
60
+ standard_libdirs.append(os.path.join(SAGE_LOCAL, "lib"))
61
+ standard_libdirs.extend(aliases["CBLAS_LIBDIR"] + aliases["NTL_LIBDIR"])
62
+ standard_incdirs = sage_include_directories() + aliases["CBLAS_INCDIR"] + aliases["NTL_INCDIR"]
63
+ return standard_libs, standard_libdirs, standard_incdirs, aliases
64
+
65
+ ################################################################
66
+ # If the user attaches a .spyx file and changes it, we have
67
+ # to reload an .so.
68
+ #
69
+ # PROBLEM: Python does not allow one to reload an .so extension module.
70
+ # Solution, we create a different .so file and load that one,
71
+ # overwriting the definitions of everything in the original .so file.
72
+ #
73
+ # HOW: By using a sequence_number for each .spyx file; we keep
74
+ # these sequence numbers in a dict.
75
+ #
76
+ ################################################################
77
+
78
+
79
+ sequence_number = {}
80
+
81
+
82
+ def cython(filename, verbose=0, compile_message=False,
83
+ use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True,
84
+ create_local_so_file=False):
85
+ r"""
86
+ Compile a Cython file. This converts a Cython file to a C (or C++ file),
87
+ and then compiles that. The .c file and the .so file are
88
+ created in a temporary directory.
89
+
90
+ INPUT:
91
+
92
+ - ``filename`` -- the name of the file to be compiled; should end with
93
+ 'pyx'
94
+
95
+ - ``verbose`` -- integer (default: 0); level of verbosity. A negative
96
+ value ensures complete silence.
97
+
98
+ - ``compile_message`` -- boolean (default: ``False``); if ``True``, print
99
+ ``'Compiling <filename>...'`` to the standard error
100
+
101
+ - ``use_cache`` -- boolean (default: ``False``); if ``True``, check the
102
+ temporary build directory to see if there is already a
103
+ corresponding .so file. If so, and if the .so file is newer than the
104
+ Cython file, don't recompile, just reuse the .so file.
105
+
106
+ - ``create_local_c_file`` -- boolean (default: ``False``); if ``True``, save a
107
+ copy of the ``.c`` or ``.cpp`` file in the current directory
108
+
109
+ - ``annotate`` -- boolean (default: ``True``); if ``True``, create an html file which
110
+ annotates the conversion from .pyx to .c. By default this is only created
111
+ in the temporary directory, but if ``create_local_c_file`` is also True,
112
+ then save a copy of the .html file in the current directory.
113
+
114
+ - ``sage_namespace`` -- boolean (default: ``True``); if ``True``, import
115
+ ``sage.all``
116
+
117
+ - ``create_local_so_file`` -- boolean (default: ``False``); if ``True``, save a
118
+ copy of the compiled .so file in the current directory
119
+
120
+ OUTPUT: a tuple ``(name, dir)`` where ``name`` is the name
121
+ of the compiled module and ``dir`` is the directory containing
122
+ the generated files.
123
+
124
+ TESTS:
125
+
126
+ Before :issue:`12975`, it would have been needed to write ``#clang c++``,
127
+ but upper case ``C++`` has resulted in an error.
128
+ Using pkgconfig to find the libraries, headers and macros. This is a
129
+ work around while waiting for :issue:`22461` which will offer a better
130
+ solution::
131
+
132
+ sage: code = [
133
+ ....: "#clang C++",
134
+ ....: "from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular",
135
+ ....: "from sage.libs.singular.polynomial cimport singular_polynomial_pow",
136
+ ....: "def test(MPolynomial_libsingular p):",
137
+ ....: " singular_polynomial_pow(&p._poly, p._poly, 2, p._parent_ring)"]
138
+ sage: cython(os.linesep.join(code))
139
+
140
+ The function ``test`` now manipulates internal C data of polynomials,
141
+ squaring them::
142
+
143
+ sage: P.<x,y>=QQ[]
144
+ sage: test(x)
145
+ sage: x
146
+ x^2
147
+
148
+ Check that compiling C++ code works::
149
+
150
+ sage: cython("# distutils: language = c++\n"+
151
+ ....: "from libcpp.vector cimport vector\n"
152
+ ....: "cdef vector[int] * v = new vector[int](4)\n")
153
+
154
+ Check that compiling C++ code works when creating a local C file,
155
+ first moving to a tempdir to avoid clutter. Before :issue:`22113`,
156
+ the create_local_c_file argument was not tested for C++ code::
157
+
158
+ sage: orig_cwd = os.getcwd()
159
+ sage: import tempfile
160
+ sage: with tempfile.TemporaryDirectory() as d:
161
+ ....: os.chdir(d)
162
+ ....: with open("test.pyx", 'w') as f:
163
+ ....: _ = f.write("# distutils: language = c++\n"
164
+ ....: "from libcpp.vector cimport vector\n"
165
+ ....: "cdef vector[int] * v = new vector[int](4)\n")
166
+ ....: output = sage.misc.cython.cython("test.pyx",
167
+ ....: create_local_c_file=True)
168
+ ....: os.chdir(orig_cwd)
169
+
170
+ Accessing a ``.pxd`` file from the current directory works::
171
+
172
+ sage: orig_cwd = os.getcwd()
173
+ sage: import tempfile
174
+ sage: with tempfile.TemporaryDirectory() as d:
175
+ ....: os.chdir(d)
176
+ ....: with open("helper.pxd", 'w') as f:
177
+ ....: _ = f.write("cdef inline int the_answer(): return 42")
178
+ ....: cython(
179
+ ....: "from helper cimport the_answer\n"
180
+ ....: "print(the_answer())"
181
+ ....: )
182
+ ....: os.chdir(orig_cwd)
183
+ 42
184
+
185
+ Warning and error messages generated by Cython are properly
186
+ handled. Warnings are only shown if verbose >= 0::
187
+
188
+ sage: code = '''
189
+ ....: def test_unreachable():
190
+ ....: raise Exception
191
+ ....: return 42
192
+ ....: '''
193
+ sage: cython(code, verbose=-1)
194
+ sage: cython(code, verbose=0)
195
+ warning: ...:4:4: Unreachable code...
196
+
197
+ sage: cython("foo = bar\n")
198
+ Traceback (most recent call last):
199
+ ...
200
+ RuntimeError: Error compiling Cython file:
201
+ ------------------------------------------------------------
202
+ ...
203
+ foo = bar
204
+ ^
205
+ ------------------------------------------------------------
206
+ <BLANKLINE>
207
+ ...:1:6: undeclared name not builtin: bar
208
+
209
+ sage: cython("cdef extern from 'no_such_header_file': pass")
210
+ Traceback (most recent call last):
211
+ ...
212
+ RuntimeError: ...
213
+
214
+ As of :issue:`29139` the default is ``cdivision=True``::
215
+
216
+ sage: cython('''
217
+ ....: cdef size_t foo = 3/2
218
+ ....: ''')
219
+
220
+ Check that Cython supports PEP 420 packages::
221
+
222
+ sage: cython('''
223
+ ....: cimport sage.misc.cachefunc
224
+ ....: ''')
225
+
226
+ sage: cython('''
227
+ ....: from sage.misc.cachefunc cimport cache_key
228
+ ....: ''')
229
+
230
+ In Cython 0.29.33 using `from PACKAGE cimport MODULE` is broken
231
+ when `PACKAGE` is a namespace package, see :issue:`35322`::
232
+
233
+ sage: cython('''
234
+ ....: from sage.misc cimport cachefunc
235
+ ....: ''')
236
+ Traceback (most recent call last):
237
+ ...
238
+ RuntimeError: Error compiling Cython file:
239
+ ...
240
+ ...: 'sage/misc.pxd' not found
241
+ """
242
+ if not filename.endswith('pyx'):
243
+ print("Warning: file (={}) should have extension .pyx".format(filename), file=sys.stderr)
244
+
245
+ # base is the name of the .so module that we create. If we are
246
+ # creating a local shared object file, we use a more natural
247
+ # naming convention. If we are not creating a local shared object
248
+ # file, the main constraint is that it is unique and determined by
249
+ # the file that we're running Cython on, so that in some cases we
250
+ # can cache the result (e.g., recompiling the same pyx file during
251
+ # the same session).
252
+ if create_local_so_file:
253
+ base, ext = os.path.splitext(os.path.basename(filename))
254
+ else:
255
+ base = os.path.abspath(filename)
256
+ base = sanitize(base)
257
+
258
+ # This is the *temporary* directory where we store the pyx file.
259
+ # spyx_tmp changes when we start Sage, so old (but not stale) pyx
260
+ # files must be rebuilt at the moment.
261
+ target_dir = os.path.join(spyx_tmp(), base)
262
+
263
+ # Build directory for Cython/distutils
264
+ build_dir = os.path.join(target_dir, "build")
265
+
266
+ if os.path.exists(target_dir):
267
+ # There is already a module here. Maybe we do not have to rebuild?
268
+ # Find the name.
269
+ if use_cache:
270
+ from importlib.machinery import EXTENSION_SUFFIXES
271
+ for f in os.listdir(target_dir):
272
+ for suffix in EXTENSION_SUFFIXES:
273
+ if f.endswith(suffix):
274
+ # use the first matching extension
275
+ prev_file = os.path.join(target_dir, f)
276
+ prev_name = f[:-len(suffix)]
277
+ break
278
+ else:
279
+ # no match, try next file
280
+ continue
281
+ if os.path.getmtime(filename) <= os.path.getmtime(prev_file):
282
+ # We do not have to rebuild.
283
+ return prev_name, target_dir
284
+
285
+ # Delete all ordinary files in target_dir
286
+ for F in os.listdir(target_dir):
287
+ G = os.path.join(target_dir, F)
288
+ if os.path.isdir(G):
289
+ continue
290
+ try:
291
+ os.unlink(G)
292
+ except OSError:
293
+ pass
294
+ else:
295
+ os.makedirs(target_dir, exist_ok=True)
296
+
297
+ if create_local_so_file:
298
+ name = base
299
+ else:
300
+ global sequence_number
301
+ if base not in sequence_number:
302
+ sequence_number[base] = 0
303
+ name = '%s_%s' % (base, sequence_number[base])
304
+
305
+ # increment the sequence number so will use a different one next time.
306
+ sequence_number[base] += 1
307
+
308
+ if compile_message:
309
+ sys.stderr.write("Compiling {}...\n".format(filename))
310
+ sys.stderr.flush()
311
+
312
+ # Copy original file to the target directory.
313
+ pyxfile = os.path.join(target_dir, name + ".pyx")
314
+ shutil.copy(filename, pyxfile)
315
+
316
+ # Add current working directory to includes. This is needed because
317
+ # we cythonize from a different directory. See Issue #24764.
318
+ standard_libs, standard_libdirs, standard_includes, aliases = _standard_libs_libdirs_incdirs_aliases()
319
+ includes = [os.getcwd()] + standard_includes
320
+
321
+ # Now do the actual build, directly calling Cython and distutils
322
+ from Cython.Build import cythonize
323
+ from Cython.Compiler.Errors import CompileError
324
+ import Cython.Compiler.Options
325
+
326
+ try:
327
+ from setuptools.dist import Distribution
328
+ from setuptools.extension import Extension
329
+ except ImportError:
330
+ # Fall back to distutils (stdlib); note that it is deprecated
331
+ # in Python 3.10, 3.11; https://www.python.org/dev/peps/pep-0632/
332
+ from distutils.dist import Distribution
333
+ from distutils.core import Extension
334
+
335
+ from distutils.log import set_verbosity
336
+ set_verbosity(verbose)
337
+
338
+ Cython.Compiler.Options.annotate = annotate
339
+ Cython.Compiler.Options.embed_pos_in_docstring = True
340
+ Cython.Compiler.Options.pre_import = "sage.all" if sage_namespace else None
341
+
342
+ extra_compile_args = ['-w'] # no warnings
343
+ extra_link_args = []
344
+
345
+ ext = Extension(name,
346
+ sources=[pyxfile],
347
+ extra_compile_args=extra_compile_args,
348
+ extra_link_args=extra_link_args,
349
+ libraries=standard_libs,
350
+ library_dirs=standard_libdirs)
351
+
352
+ directives = {'language_level': 3, 'cdivision': True}
353
+
354
+ try:
355
+ # Change directories to target_dir so that Cython produces the correct
356
+ # relative path; https://github.com/sagemath/sage/issues/24097
357
+ with restore_cwd(target_dir):
358
+ try:
359
+ from sage.misc.package_dir import cython_namespace_package_support
360
+ with cython_namespace_package_support():
361
+ ext, = cythonize([ext],
362
+ aliases=aliases,
363
+ include_path=includes,
364
+ compiler_directives=directives,
365
+ quiet=(verbose <= 0),
366
+ errors_to_stderr=False,
367
+ use_listing_file=True)
368
+ finally:
369
+ # Read the "listing file" which is the file containing
370
+ # warning and error messages generated by Cython.
371
+ try:
372
+ with open(name + ".lis") as f:
373
+ cython_messages = f.read()
374
+ except OSError:
375
+ cython_messages = "Error compiling Cython file"
376
+ except CompileError:
377
+ raise RuntimeError(cython_messages.strip())
378
+
379
+ if verbose >= 0:
380
+ # triggered by Cython 3 with unpatched cysignals 1.11.2
381
+ cython_messages = re.sub(
382
+ "^.*The keyword 'nogil' should appear at the end of the function signature line. "
383
+ "Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n",
384
+ "", cython_messages, 0, re.MULTILINE)
385
+
386
+ sys.stderr.write(cython_messages)
387
+ sys.stderr.flush()
388
+
389
+ if create_local_c_file:
390
+ shutil.copy(os.path.join(target_dir, ext.sources[0]),
391
+ os.curdir)
392
+ if annotate:
393
+ shutil.copy(os.path.join(target_dir, name + ".html"),
394
+ os.curdir)
395
+
396
+ # This emulates running "setup.py build" with the correct options
397
+ #
398
+ # setuptools plugins considered harmful:
399
+ # If build isolation is not in use and setuptools_scm is installed,
400
+ # then its file_finders entry point is invoked, which we don't need.
401
+ # And with setuptools_scm 8, we get more trouble:
402
+ # LookupError: pyproject.toml does not contain a tool.setuptools_scm section
403
+ # LookupError: setuptools-scm was unable to detect version ...
404
+ # We just remove all handling of "setuptools.finalize_distribution_options" entry points.
405
+ class Distribution_no_finalize_distribution_options(Distribution):
406
+ @staticmethod
407
+ def _removed(ep):
408
+ return True
409
+
410
+ dist = Distribution_no_finalize_distribution_options()
411
+ dist.ext_modules = [ext]
412
+ dist.include_dirs = includes
413
+ buildcmd = dist.get_command_obj("build")
414
+ buildcmd.build_base = build_dir
415
+ buildcmd.build_lib = target_dir
416
+
417
+ try:
418
+ # Capture errors from distutils and its child processes
419
+ with open(os.path.join(target_dir, name + ".err"), 'w+') as errfile:
420
+ try:
421
+ # Redirect stderr to errfile. We use the file descriptor
422
+ # number "2" instead of "sys.stderr" because we really
423
+ # want to redirect the messages from GCC. These are sent
424
+ # to the actual stderr, regardless of what sys.stderr is.
425
+ sys.stderr.flush()
426
+ with redirection(2, errfile, close=False):
427
+ dist.run_command("build")
428
+ finally:
429
+ errfile.seek(0)
430
+ distutils_messages = errfile.read()
431
+ except Exception as msg:
432
+ msg = str(msg) + "\n" + distutils_messages
433
+ raise RuntimeError(msg.strip())
434
+
435
+ if verbose >= 0:
436
+ sys.stderr.write(distutils_messages)
437
+ sys.stderr.flush()
438
+
439
+ if create_local_so_file:
440
+ # Copy module to current directory
441
+ from importlib.machinery import EXTENSION_SUFFIXES
442
+ for ext in EXTENSION_SUFFIXES:
443
+ path = os.path.join(target_dir, name + ext)
444
+ if os.path.exists(path):
445
+ shutil.copy(path, os.curdir)
446
+
447
+ return name, target_dir
448
+
449
+
450
+ ################################################################
451
+ # COMPILE
452
+ ################################################################
453
+ def cython_lambda(vars, expr, verbose=0, **kwds):
454
+ """
455
+ Create a compiled function which evaluates ``expr`` assuming machine values
456
+ for ``vars``.
457
+
458
+ INPUT:
459
+
460
+ - ``vars`` -- list of pairs (variable name, c-data type), where the variable
461
+ names and data types are strings, OR a string such as ``'double x, int y,
462
+ int z'``
463
+
464
+ - ``expr`` -- an expression involving the vars and constants; you can access
465
+ objects defined in the current module scope ``globals()`` using
466
+ ``sage.object_name``.
467
+
468
+ .. warning::
469
+
470
+ Accessing ``globals()`` doesn't actually work, see :issue:`12446`.
471
+
472
+ EXAMPLES:
473
+
474
+ We create a Lambda function in pure Python (using the r to make sure the 3.2
475
+ is viewed as a Python float)::
476
+
477
+ sage: f = lambda x,y: x*x + y*y + x + y + 17r*x + 3.2r
478
+
479
+ We make the same Lambda function, but in a compiled form. ::
480
+
481
+ sage: g = cython_lambda('double x, double y', 'x*x + y*y + x + y + 17*x + 3.2')
482
+ sage: g(2,3)
483
+ 55.2
484
+ sage: g(0,0)
485
+ 3.2
486
+
487
+ In order to access Sage globals, prefix them with ``sage.``::
488
+
489
+ sage: f = cython_lambda('double x', 'sage.sin(x) + sage.a')
490
+ sage: f(0)
491
+ Traceback (most recent call last):
492
+ ...
493
+ NameError: global 'a' is not defined
494
+ sage: a = 25
495
+ sage: f(10)
496
+ 24.45597888911063
497
+ sage: a = 50
498
+ sage: f(10)
499
+ 49.45597888911063
500
+ """
501
+ if isinstance(vars, str):
502
+ v = vars
503
+ else:
504
+ v = ', '.join('%s %s' % (typ, var) for typ, var in vars)
505
+
506
+ s = """
507
+ cdef class _s:
508
+ cdef globals
509
+
510
+ def __init__(self):
511
+ from sage.repl.user_globals import get_globals
512
+ self.globals = get_globals()
513
+
514
+ def __getattr__(self, name):
515
+ try:
516
+ return self.globals[name]
517
+ except KeyError:
518
+ raise NameError("global {!r} is not defined".format(name))
519
+
520
+ sage = _s()
521
+
522
+ def f(%s):
523
+ return %s
524
+ """ % (v, expr)
525
+ if verbose > 0:
526
+ print(s)
527
+ tmpfile = tmp_filename(ext='.pyx')
528
+ with open(tmpfile, 'w') as f:
529
+ f.write(s)
530
+
531
+ d = {}
532
+ cython_import_all(tmpfile, d, verbose=verbose, **kwds)
533
+ return d['f']
534
+
535
+
536
+ ################################################################
537
+ # IMPORT
538
+ ################################################################
539
+ def cython_import(filename, **kwds):
540
+ """
541
+ Compile a file containing Cython code, then import and return the
542
+ module. Raises an :exc:`ImportError` if anything goes wrong.
543
+
544
+ INPUT:
545
+
546
+ - ``filename`` -- string; name of a file that contains Cython
547
+ code
548
+
549
+ See the function :func:`sage.misc.cython.cython` for documentation
550
+ for the other inputs.
551
+
552
+ OUTPUT: the module that contains the compiled Cython code
553
+ """
554
+ name, build_dir = cython(filename, **kwds)
555
+
556
+ oldpath = sys.path
557
+ try:
558
+ sys.path.append(build_dir)
559
+ return builtins.__import__(name)
560
+ except ModuleNotFoundError:
561
+ import importlib
562
+ importlib.invalidate_caches()
563
+ return builtins.__import__(name)
564
+ finally:
565
+ sys.path = oldpath
566
+
567
+
568
+ def cython_import_all(filename, globals, **kwds):
569
+ """
570
+ Imports all non-private (i.e., not beginning with an underscore)
571
+ attributes of the specified Cython module into the given context.
572
+ This is similar to::
573
+
574
+ from module import *
575
+
576
+ Raises an :exc:`ImportError` exception if anything goes wrong.
577
+
578
+ INPUT:
579
+
580
+ - ``filename`` -- string; name of a file that contains Cython
581
+ code
582
+ """
583
+ m = cython_import(filename, **kwds)
584
+ for k, x in m.__dict__.items():
585
+ if k[0] != '_':
586
+ globals[k] = x
587
+
588
+
589
+ def sanitize(f):
590
+ """
591
+ Given a filename ``f``, replace it by a filename that is a valid Python
592
+ module name.
593
+
594
+ This means that the characters are all alphanumeric or ``_``'s and doesn't
595
+ begin with a numeral.
596
+
597
+ EXAMPLES::
598
+
599
+ sage: from sage.misc.cython import sanitize
600
+ sage: sanitize('abc')
601
+ 'abc'
602
+ sage: sanitize('abc/def')
603
+ 'abc_def'
604
+ sage: sanitize('123/def-hij/file.py')
605
+ '_123_def_hij_file_py'
606
+ """
607
+ s = ''
608
+ if f[0].isdigit():
609
+ s += '_'
610
+ for a in f:
611
+ if a.isalnum():
612
+ s += a
613
+ else:
614
+ s += '_'
615
+ return s
616
+
617
+
618
+ def compile_and_load(code, **kwds):
619
+ r"""
620
+ INPUT:
621
+
622
+ - ``code`` -- string containing code that could be in a .pyx file
623
+ that is attached or put in a %cython block in the notebook
624
+
625
+ OUTPUT: a module, which results from compiling the given code and
626
+ importing it
627
+
628
+ EXAMPLES::
629
+
630
+ sage: from sage.misc.cython import compile_and_load
631
+ sage: module = compile_and_load("def f(int n):\n return n*n")
632
+ sage: module.f(10)
633
+ 100
634
+
635
+ TESTS::
636
+
637
+ sage: code = '''
638
+ ....: from sage.rings.rational cimport Rational
639
+ ....: from sage.rings.polynomial.polynomial_rational_flint cimport Polynomial_rational_flint
640
+ ....: from sage.libs.flint.fmpq_poly cimport fmpq_poly_length
641
+ ....: from sage.libs.flint.fmpq_poly_sage cimport fmpq_poly_get_coeff_mpq, fmpq_poly_set_coeff_mpq
642
+ ....:
643
+ ....: def evaluate_at_power_of_gen(Polynomial_rational_flint f, unsigned long n):
644
+ ....: assert n >= 1
645
+ ....: cdef Polynomial_rational_flint res = f._new()
646
+ ....: cdef unsigned long k
647
+ ....: cdef Rational z = Rational(0)
648
+ ....: for k in range(fmpq_poly_length(f._poly)):
649
+ ....: fmpq_poly_get_coeff_mpq(z.value, f._poly, k)
650
+ ....: fmpq_poly_set_coeff_mpq(res._poly, n*k, z.value)
651
+ ....: return res
652
+ ....: '''
653
+ sage: module = compile_and_load(code) # long time
654
+ sage: R.<x> = QQ[]
655
+ sage: module.evaluate_at_power_of_gen(x^3 + x - 7, 5) # long time
656
+ x^15 + x^5 - 7
657
+ """
658
+ tmpfile = tmp_filename(ext='.pyx')
659
+ with open(tmpfile, 'w') as f:
660
+ f.write(code)
661
+ return cython_import(tmpfile, **kwds)
662
+
663
+
664
+ def cython_compile(code, **kwds):
665
+ """
666
+ Given a block of Cython code (as a text string), this function
667
+ compiles it using a C compiler, and includes it into the global
668
+ namespace.
669
+
670
+ AUTHOR: William Stein, 2006-10-31
671
+
672
+ .. WARNING::
673
+
674
+ Only use this from Python code, not from extension code, since
675
+ from extension code you would change the global scope (i.e.,
676
+ of the Sage interpreter). And it would be stupid, since you're
677
+ already writing Cython!
678
+
679
+ Also, never use this in the standard Sage library. Any code
680
+ that uses this can only run on a system that has a C compiler
681
+ installed, and we want to avoid making that assumption for
682
+ casual Sage usage. Also, any code that uses this in the
683
+ library would greatly slow down startup time, since currently
684
+ there is no caching.
685
+
686
+ .. TODO::
687
+
688
+ Need to create a clever caching system so code only gets
689
+ compiled once.
690
+ """
691
+ tmpfile = tmp_filename(ext='.pyx')
692
+ with open(tmpfile, 'w') as f:
693
+ f.write(code)
694
+ return cython_import_all(tmpfile, get_globals(), **kwds)