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.
- passagemath_repl-10.4.62.data/scripts/sage-cachegrind +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-callgrind +16 -0
- passagemath_repl-10.4.62.data/scripts/sage-cleaner +230 -0
- passagemath_repl-10.4.62.data/scripts/sage-coverage +327 -0
- passagemath_repl-10.4.62.data/scripts/sage-eval +14 -0
- passagemath_repl-10.4.62.data/scripts/sage-fixdoctests +708 -0
- passagemath_repl-10.4.62.data/scripts/sage-inline-fortran +12 -0
- passagemath_repl-10.4.62.data/scripts/sage-ipynb2rst +50 -0
- passagemath_repl-10.4.62.data/scripts/sage-ipython +16 -0
- passagemath_repl-10.4.62.data/scripts/sage-massif +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-notebook +267 -0
- passagemath_repl-10.4.62.data/scripts/sage-omega +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-preparse +302 -0
- passagemath_repl-10.4.62.data/scripts/sage-run +27 -0
- passagemath_repl-10.4.62.data/scripts/sage-run-cython +10 -0
- passagemath_repl-10.4.62.data/scripts/sage-runtests +9 -0
- passagemath_repl-10.4.62.data/scripts/sage-startuptime.py +163 -0
- passagemath_repl-10.4.62.data/scripts/sage-valgrind +34 -0
- passagemath_repl-10.4.62.dist-info/METADATA +77 -0
- passagemath_repl-10.4.62.dist-info/RECORD +162 -0
- passagemath_repl-10.4.62.dist-info/WHEEL +5 -0
- passagemath_repl-10.4.62.dist-info/top_level.txt +1 -0
- sage/all__sagemath_repl.py +119 -0
- sage/doctest/__init__.py +4 -0
- sage/doctest/__main__.py +236 -0
- sage/doctest/all.py +4 -0
- sage/doctest/check_tolerance.py +261 -0
- sage/doctest/control.py +1727 -0
- sage/doctest/external.py +534 -0
- sage/doctest/fixtures.py +383 -0
- sage/doctest/forker.py +2665 -0
- sage/doctest/marked_output.py +102 -0
- sage/doctest/parsing.py +1708 -0
- sage/doctest/parsing_test.py +79 -0
- sage/doctest/reporting.py +733 -0
- sage/doctest/rif_tol.py +124 -0
- sage/doctest/sources.py +1657 -0
- sage/doctest/test.py +584 -0
- sage/doctest/tests/1second.rst +4 -0
- sage/doctest/tests/99seconds.rst +4 -0
- sage/doctest/tests/abort.rst +5 -0
- sage/doctest/tests/atexit.rst +7 -0
- sage/doctest/tests/fail_and_die.rst +6 -0
- sage/doctest/tests/initial.rst +15 -0
- sage/doctest/tests/interrupt.rst +7 -0
- sage/doctest/tests/interrupt_diehard.rst +14 -0
- sage/doctest/tests/keyboardinterrupt.rst +11 -0
- sage/doctest/tests/longtime.rst +5 -0
- sage/doctest/tests/nodoctest +5 -0
- sage/doctest/tests/random_seed.rst +4 -0
- sage/doctest/tests/show_skipped.rst +18 -0
- sage/doctest/tests/sig_on.rst +9 -0
- sage/doctest/tests/simple_failure.rst +8 -0
- sage/doctest/tests/sleep_and_raise.rst +106 -0
- sage/doctest/tests/tolerance.rst +31 -0
- sage/doctest/util.py +750 -0
- sage/interfaces/cleaner.py +48 -0
- sage/interfaces/quit.py +163 -0
- sage/misc/all__sagemath_repl.py +51 -0
- sage/misc/banner.py +235 -0
- sage/misc/benchmark.py +221 -0
- sage/misc/classgraph.py +131 -0
- sage/misc/copying.py +22 -0
- sage/misc/cython.py +694 -0
- sage/misc/dev_tools.py +745 -0
- sage/misc/edit_module.py +304 -0
- sage/misc/explain_pickle.py +3079 -0
- sage/misc/gperftools.py +361 -0
- sage/misc/inline_fortran.py +212 -0
- sage/misc/messaging.py +86 -0
- sage/misc/pager.py +21 -0
- sage/misc/profiler.py +179 -0
- sage/misc/python.py +70 -0
- sage/misc/remote_file.py +53 -0
- sage/misc/sage_eval.py +246 -0
- sage/misc/sage_input.py +3621 -0
- sage/misc/sagedoc.py +1742 -0
- sage/misc/sh.py +38 -0
- sage/misc/trace.py +90 -0
- sage/repl/__init__.py +16 -0
- sage/repl/all.py +15 -0
- sage/repl/attach.py +625 -0
- sage/repl/configuration.py +186 -0
- sage/repl/display/__init__.py +1 -0
- sage/repl/display/fancy_repr.py +354 -0
- sage/repl/display/formatter.py +318 -0
- sage/repl/display/jsmol_iframe.py +290 -0
- sage/repl/display/pretty_print.py +153 -0
- sage/repl/display/util.py +163 -0
- sage/repl/image.py +302 -0
- sage/repl/inputhook.py +91 -0
- sage/repl/interface_magic.py +298 -0
- sage/repl/interpreter.py +854 -0
- sage/repl/ipython_extension.py +593 -0
- sage/repl/ipython_kernel/__init__.py +1 -0
- sage/repl/ipython_kernel/__main__.py +4 -0
- sage/repl/ipython_kernel/all_jupyter.py +10 -0
- sage/repl/ipython_kernel/install.py +301 -0
- sage/repl/ipython_kernel/interact.py +278 -0
- sage/repl/ipython_kernel/kernel.py +217 -0
- sage/repl/ipython_kernel/widgets.py +466 -0
- sage/repl/ipython_kernel/widgets_sagenb.py +587 -0
- sage/repl/ipython_tests.py +163 -0
- sage/repl/load.py +326 -0
- sage/repl/preparse.py +2218 -0
- sage/repl/prompts.py +90 -0
- sage/repl/rich_output/__init__.py +4 -0
- sage/repl/rich_output/backend_base.py +648 -0
- sage/repl/rich_output/backend_doctest.py +316 -0
- sage/repl/rich_output/backend_emacs.py +151 -0
- sage/repl/rich_output/backend_ipython.py +596 -0
- sage/repl/rich_output/buffer.py +311 -0
- sage/repl/rich_output/display_manager.py +829 -0
- sage/repl/rich_output/example.avi +0 -0
- sage/repl/rich_output/example.canvas3d +1 -0
- sage/repl/rich_output/example.dvi +0 -0
- sage/repl/rich_output/example.flv +0 -0
- sage/repl/rich_output/example.gif +0 -0
- sage/repl/rich_output/example.jpg +0 -0
- sage/repl/rich_output/example.mkv +0 -0
- sage/repl/rich_output/example.mov +0 -0
- sage/repl/rich_output/example.mp4 +0 -0
- sage/repl/rich_output/example.ogv +0 -0
- sage/repl/rich_output/example.pdf +0 -0
- sage/repl/rich_output/example.png +0 -0
- sage/repl/rich_output/example.svg +54 -0
- sage/repl/rich_output/example.webm +0 -0
- sage/repl/rich_output/example.wmv +0 -0
- sage/repl/rich_output/example_jmol.spt.zip +0 -0
- sage/repl/rich_output/example_wavefront_scene.mtl +7 -0
- sage/repl/rich_output/example_wavefront_scene.obj +17 -0
- sage/repl/rich_output/output_basic.py +391 -0
- sage/repl/rich_output/output_browser.py +103 -0
- sage/repl/rich_output/output_catalog.py +54 -0
- sage/repl/rich_output/output_graphics.py +320 -0
- sage/repl/rich_output/output_graphics3d.py +345 -0
- sage/repl/rich_output/output_video.py +231 -0
- sage/repl/rich_output/preferences.py +432 -0
- sage/repl/rich_output/pretty_print.py +339 -0
- sage/repl/rich_output/test_backend.py +201 -0
- sage/repl/user_globals.py +214 -0
- sage/tests/__init__.py +1 -0
- sage/tests/all.py +3 -0
- sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +630 -0
- sage/tests/arxiv_0812_2725.py +351 -0
- sage/tests/benchmark.py +1923 -0
- sage/tests/book_schilling_zabrocki_kschur_primer.py +795 -0
- sage/tests/book_stein_ent.py +651 -0
- sage/tests/book_stein_modform.py +558 -0
- sage/tests/cmdline.py +790 -0
- sage/tests/combinatorial_hopf_algebras.py +52 -0
- sage/tests/finite_poset.py +623 -0
- sage/tests/functools_partial_src.py +27 -0
- sage/tests/gosper-sum.py +218 -0
- sage/tests/lazy_imports.py +28 -0
- sage/tests/modular_group_cohomology.py +80 -0
- sage/tests/numpy.py +21 -0
- sage/tests/parigp.py +76 -0
- sage/tests/startup.py +27 -0
- sage/tests/symbolic-series.py +76 -0
- sage/tests/sympy.py +16 -0
- sage/tests/test_deprecation.py +31 -0
sage/misc/gperftools.py
ADDED
@@ -0,0 +1,361 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
# sage.doctest: needs sage.symbolic
|
3
|
+
"""
|
4
|
+
C Function Profiler Using Google Perftools
|
5
|
+
|
6
|
+
Note that the profiler samples 100x per second by default. In
|
7
|
+
particular, you cannot profile anything shorter than 10ms. You can
|
8
|
+
adjust the rate with the ``CPUPROFILE_FREQUENCY`` environment variable
|
9
|
+
if you want to change it.
|
10
|
+
|
11
|
+
EXAMPLES::
|
12
|
+
|
13
|
+
sage: from sage.misc.gperftools import Profiler, run_100ms
|
14
|
+
sage: prof = Profiler()
|
15
|
+
sage: prof.start() # optional - gperftools
|
16
|
+
sage: run_100ms()
|
17
|
+
sage: prof.stop() # optional - gperftools
|
18
|
+
PROFILE: interrupts/evictions/bytes = ...
|
19
|
+
|
20
|
+
REFERENCE:
|
21
|
+
|
22
|
+
Uses the `Google performance analysis tools
|
23
|
+
<https://github.com/gperftools/gperftools>`_. Note that they are not
|
24
|
+
included in Sage, you have to install them yourself on your system.
|
25
|
+
|
26
|
+
AUTHORS:
|
27
|
+
|
28
|
+
- Volker Braun (2014-03-31): initial version
|
29
|
+
"""
|
30
|
+
|
31
|
+
# ****************************************************************************
|
32
|
+
# Copyright (C) 2014 Volker Braun <vbraun.name@gmail.com>
|
33
|
+
#
|
34
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
35
|
+
#
|
36
|
+
# https://www.gnu.org/licenses/
|
37
|
+
# ****************************************************************************
|
38
|
+
|
39
|
+
import sys
|
40
|
+
import ctypes
|
41
|
+
import time
|
42
|
+
from sage.structure.sage_object import SageObject
|
43
|
+
from sage.misc.cachefunc import cached_method
|
44
|
+
from sage.misc.compat import find_library
|
45
|
+
from sage.cpython.string import bytes_to_str
|
46
|
+
|
47
|
+
|
48
|
+
libc = None
|
49
|
+
libprofiler = None
|
50
|
+
|
51
|
+
|
52
|
+
class Profiler(SageObject):
|
53
|
+
|
54
|
+
def __init__(self, filename=None):
|
55
|
+
"""
|
56
|
+
Interface to the gperftools profiler.
|
57
|
+
|
58
|
+
INPUT:
|
59
|
+
|
60
|
+
- ``filename`` -- string or ``None`` (default). The file name
|
61
|
+
to log to. By default, a new temporary file is created.
|
62
|
+
|
63
|
+
EXAMPLES::
|
64
|
+
|
65
|
+
sage: from sage.misc.gperftools import Profiler
|
66
|
+
sage: Profiler()
|
67
|
+
Profiler logging to ...
|
68
|
+
"""
|
69
|
+
if filename is None:
|
70
|
+
from sage.misc.temporary_file import tmp_filename
|
71
|
+
self._filename = tmp_filename(ext='.perf')
|
72
|
+
else:
|
73
|
+
self._filename = filename
|
74
|
+
|
75
|
+
def filename(self):
|
76
|
+
"""
|
77
|
+
Return the file name.
|
78
|
+
|
79
|
+
OUTPUT: string
|
80
|
+
|
81
|
+
EXAMPLES::
|
82
|
+
|
83
|
+
sage: from sage.misc.gperftools import Profiler
|
84
|
+
sage: prof = Profiler()
|
85
|
+
sage: prof.filename()
|
86
|
+
'.../tmp_....perf'
|
87
|
+
"""
|
88
|
+
return self._filename
|
89
|
+
|
90
|
+
def _repr_(self):
|
91
|
+
"""
|
92
|
+
Return string representation.
|
93
|
+
|
94
|
+
OUTPUT: string
|
95
|
+
|
96
|
+
EXAMPLES::
|
97
|
+
|
98
|
+
sage: from sage.misc.gperftools import Profiler
|
99
|
+
sage: Profiler()
|
100
|
+
Profiler logging to .../tmp....perf
|
101
|
+
"""
|
102
|
+
return 'Profiler logging to {0}'.format(self.filename())
|
103
|
+
|
104
|
+
def _libprofiler(self):
|
105
|
+
"""
|
106
|
+
Return libprofiler.
|
107
|
+
|
108
|
+
OUTPUT: a ctypes shared library handle
|
109
|
+
|
110
|
+
EXAMPLES::
|
111
|
+
|
112
|
+
sage: from sage.misc.gperftools import Profiler
|
113
|
+
sage: Profiler()._libprofiler() # optional - gperftools
|
114
|
+
<CDLL 'libprofiler...', handle ... at ...>
|
115
|
+
"""
|
116
|
+
global libprofiler
|
117
|
+
if libprofiler is not None:
|
118
|
+
return libprofiler
|
119
|
+
import ctypes.util
|
120
|
+
name = ctypes.util.find_library('profiler')
|
121
|
+
if name:
|
122
|
+
libprofiler = ctypes.CDLL(name)
|
123
|
+
return libprofiler
|
124
|
+
else:
|
125
|
+
raise ImportError('failed to open libprofiler, make sure gperftools is installed')
|
126
|
+
|
127
|
+
def start(self):
|
128
|
+
"""
|
129
|
+
Start profiling.
|
130
|
+
|
131
|
+
EXAMPLES::
|
132
|
+
|
133
|
+
sage: from sage.misc.gperftools import Profiler, run_100ms
|
134
|
+
sage: prof = Profiler()
|
135
|
+
sage: prof.start() # optional - gperftools
|
136
|
+
sage: run_100ms()
|
137
|
+
sage: prof.stop() # optional - gperftools
|
138
|
+
PROFILE: interrupts/evictions/bytes = ...
|
139
|
+
"""
|
140
|
+
from signal import SIGPROF, SIG_DFL
|
141
|
+
from cysignals.pysignals import setossignal
|
142
|
+
self._previous_sigprof_handler = setossignal(SIGPROF, SIG_DFL)
|
143
|
+
profiler = self._libprofiler()
|
144
|
+
self._t_start = time.time()
|
145
|
+
rc = profiler.ProfilerStart(str.encode(self.filename()))
|
146
|
+
if rc < 0:
|
147
|
+
raise ValueError('profiler failed to start')
|
148
|
+
|
149
|
+
def stop(self):
|
150
|
+
"""
|
151
|
+
Stop the CPU profiler.
|
152
|
+
|
153
|
+
EXAMPLES::
|
154
|
+
|
155
|
+
sage: from sage.misc.gperftools import Profiler, run_100ms
|
156
|
+
sage: prof = Profiler()
|
157
|
+
sage: prof.start() # optional - gperftools
|
158
|
+
sage: run_100ms()
|
159
|
+
sage: prof.stop() # optional - gperftools
|
160
|
+
PROFILE: interrupts/evictions/bytes = ...
|
161
|
+
"""
|
162
|
+
profiler = self._libprofiler()
|
163
|
+
profiler.ProfilerStop()
|
164
|
+
self._t_stop = time.time()
|
165
|
+
if (self._t_stop - self._t_start) < 0.1:
|
166
|
+
from warnings import warn
|
167
|
+
warn('not enough samples, total runtime was '
|
168
|
+
'less than 100ms', RuntimeWarning)
|
169
|
+
|
170
|
+
@cached_method
|
171
|
+
def _pprof(self):
|
172
|
+
"""
|
173
|
+
Return the name of the ``pprof`` binary.
|
174
|
+
|
175
|
+
OUTPUT:
|
176
|
+
|
177
|
+
String. The name of the gperftools ``pprof`` utility. A
|
178
|
+
:exc:`OSError` is raised if it cannot be found.
|
179
|
+
|
180
|
+
EXAMPLES::
|
181
|
+
|
182
|
+
sage: from sage.misc.gperftools import Profiler
|
183
|
+
sage: prof = Profiler()
|
184
|
+
sage: try:
|
185
|
+
....: pp = prof._pprof()
|
186
|
+
....: assert isinstance(pp, str)
|
187
|
+
....: except OSError:
|
188
|
+
....: pass # not installed
|
189
|
+
"""
|
190
|
+
potential_names = ['google-pprof', 'pprof']
|
191
|
+
from subprocess import check_output, CalledProcessError, STDOUT
|
192
|
+
for name in potential_names:
|
193
|
+
try:
|
194
|
+
version = check_output([name, '--version'], stderr=STDOUT)
|
195
|
+
except (CalledProcessError, OSError):
|
196
|
+
continue
|
197
|
+
version = bytes_to_str(version)
|
198
|
+
if 'gperftools' not in version:
|
199
|
+
from warnings import warn
|
200
|
+
warn('the "{0}" utility does not appear to be the gperftools profiler'
|
201
|
+
.format(name), RuntimeWarning)
|
202
|
+
continue
|
203
|
+
return name
|
204
|
+
raise OSError('unable to run pprof, please install gperftools')
|
205
|
+
|
206
|
+
def _executable(self):
|
207
|
+
"""
|
208
|
+
Return the name of the Sage Python interpreter.
|
209
|
+
|
210
|
+
OUTPUT: string
|
211
|
+
|
212
|
+
EXAMPLES::
|
213
|
+
|
214
|
+
sage: from sage.misc.gperftools import Profiler
|
215
|
+
sage: prof = Profiler()
|
216
|
+
sage: prof._executable()
|
217
|
+
'.../python...'
|
218
|
+
"""
|
219
|
+
return sys.executable
|
220
|
+
|
221
|
+
def _call_pprof(self, *args, **kwds):
|
222
|
+
"""
|
223
|
+
Run the pprof binary.
|
224
|
+
|
225
|
+
INPUT:
|
226
|
+
|
227
|
+
- ``args`` -- list of strings; the arguments to ``pprof``
|
228
|
+
|
229
|
+
- ``kwds`` -- keyword arguments passed to ``subprocess.check_call``
|
230
|
+
|
231
|
+
EXAMPLES::
|
232
|
+
|
233
|
+
sage: from sage.misc.gperftools import Profiler
|
234
|
+
sage: prof = Profiler()
|
235
|
+
sage: prof._call_pprof('--help') # optional - gperftools
|
236
|
+
Usage:
|
237
|
+
pprof [options] <program> <profiles>
|
238
|
+
...
|
239
|
+
"""
|
240
|
+
from subprocess import check_call
|
241
|
+
check_call([self._pprof()] + list(args), **kwds)
|
242
|
+
|
243
|
+
def top(self, cumulative=True):
|
244
|
+
"""
|
245
|
+
Print text report.
|
246
|
+
|
247
|
+
OUTPUT: nothing; a textual report is printed to stdout
|
248
|
+
|
249
|
+
EXAMPLES::
|
250
|
+
|
251
|
+
sage: from sage.misc.gperftools import Profiler
|
252
|
+
sage: prof = Profiler()
|
253
|
+
sage: prof.start() # optional - gperftools
|
254
|
+
sage: # do something
|
255
|
+
sage: prof.stop() # optional - gperftools
|
256
|
+
PROFILE: interrupts/evictions/bytes = ...
|
257
|
+
sage: prof.top() # optional - gperftools
|
258
|
+
Using local file ...
|
259
|
+
Using local file ...
|
260
|
+
"""
|
261
|
+
args = []
|
262
|
+
if cumulative:
|
263
|
+
args += ['--cum']
|
264
|
+
args += ['--text', self._executable(), self.filename()]
|
265
|
+
self._call_pprof(*args)
|
266
|
+
|
267
|
+
def save(self, filename, cumulative=True, verbose=True):
|
268
|
+
"""
|
269
|
+
Save report to disk.
|
270
|
+
|
271
|
+
INPUT:
|
272
|
+
|
273
|
+
- ``filename`` -- string; the filename to save at. Must end
|
274
|
+
with one of ``.dot``, ``.ps``, ``.pdf``, ``.svg``, ``.gif``,
|
275
|
+
or ``.txt`` to specify the output file format.
|
276
|
+
|
277
|
+
- ``cumulative`` -- boolean (default: ``True``); whether to return
|
278
|
+
cumulative timings
|
279
|
+
|
280
|
+
- ``verbose`` -- boolean (default: ``True``); whether to print
|
281
|
+
informational messages
|
282
|
+
|
283
|
+
EXAMPLES::
|
284
|
+
|
285
|
+
sage: from sage.misc.gperftools import Profiler, run_100ms
|
286
|
+
sage: prof = Profiler()
|
287
|
+
sage: prof.start() # optional - gperftools
|
288
|
+
sage: run_100ms() # optional - gperftools
|
289
|
+
sage: prof.stop() # optional - gperftools
|
290
|
+
PROFILE: interrupts/evictions/bytes = ...
|
291
|
+
sage: f = tmp_filename(ext='.txt') # optional - gperftools
|
292
|
+
sage: prof.save(f, verbose=False) # optional - gperftools
|
293
|
+
"""
|
294
|
+
args = []
|
295
|
+
if cumulative:
|
296
|
+
args += ['--cum']
|
297
|
+
if filename.endswith('.dot'):
|
298
|
+
args += ['--dot']
|
299
|
+
elif filename.endswith('.ps'):
|
300
|
+
args += ['--ps']
|
301
|
+
elif filename.endswith('.pdf'):
|
302
|
+
args += ['--pdf']
|
303
|
+
elif filename.endswith('.svg'):
|
304
|
+
args += ['--svg']
|
305
|
+
elif filename.endswith('.txt'):
|
306
|
+
args += ['--text']
|
307
|
+
elif filename.endswith('.gif'):
|
308
|
+
args += ['--gif']
|
309
|
+
else:
|
310
|
+
raise ValueError('unknown extension')
|
311
|
+
args += [self._executable(), self.filename()]
|
312
|
+
stderr = sys.stdout if verbose else False
|
313
|
+
with open(filename, 'wb') as outfile:
|
314
|
+
self._call_pprof(*args, stdout=outfile, stderr=stderr)
|
315
|
+
|
316
|
+
|
317
|
+
def crun(s, evaluator):
|
318
|
+
"""
|
319
|
+
Profile single statement.
|
320
|
+
|
321
|
+
- ``s`` -- string; Sage code to profile
|
322
|
+
|
323
|
+
- ``evaluator`` -- callable to evaluate
|
324
|
+
|
325
|
+
EXAMPLES::
|
326
|
+
|
327
|
+
sage: import sage.misc.gperftools as gperf
|
328
|
+
sage: ev = lambda ex:eval(ex, globals(), locals())
|
329
|
+
sage: gperf.crun('gperf.run_100ms()', evaluator=ev) # optional - gperftools
|
330
|
+
PROFILE: interrupts/evictions/bytes = ...
|
331
|
+
Using local file ...
|
332
|
+
Using local file ...
|
333
|
+
"""
|
334
|
+
prof = Profiler()
|
335
|
+
from sage.repl.preparse import preparse
|
336
|
+
py_s = preparse(s)
|
337
|
+
prof.start()
|
338
|
+
try:
|
339
|
+
evaluator(py_s)
|
340
|
+
finally:
|
341
|
+
prof.stop()
|
342
|
+
prof.top()
|
343
|
+
|
344
|
+
|
345
|
+
def run_100ms():
|
346
|
+
"""
|
347
|
+
Used for doctesting.
|
348
|
+
|
349
|
+
A function that performs some computation for more than (but not
|
350
|
+
that much more than) 100ms.
|
351
|
+
|
352
|
+
EXAMPLES::
|
353
|
+
|
354
|
+
sage: from sage.misc.gperftools import run_100ms
|
355
|
+
sage: run_100ms()
|
356
|
+
"""
|
357
|
+
t0 = time.time() # start
|
358
|
+
t1 = t0 + 0.1 # end
|
359
|
+
from sage.symbolic.ring import SR
|
360
|
+
while time.time() < t1:
|
361
|
+
sum(1 / (1 + SR(n) ** 2) for n in range(100))
|
@@ -0,0 +1,212 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
"""
|
3
|
+
Fortran compiler
|
4
|
+
"""
|
5
|
+
|
6
|
+
import importlib
|
7
|
+
import os
|
8
|
+
import shutil
|
9
|
+
import subprocess
|
10
|
+
import sys
|
11
|
+
|
12
|
+
from sage.misc.temporary_file import tmp_dir
|
13
|
+
|
14
|
+
|
15
|
+
def _import_module_from_path(name, path=None):
|
16
|
+
"""
|
17
|
+
Import the module named ``name`` by searching the given path entries (or
|
18
|
+
`sys.path` by default).
|
19
|
+
|
20
|
+
Returns a fully executed module object without inserting that module into
|
21
|
+
`sys.modules`.
|
22
|
+
|
23
|
+
EXAMPLES::
|
24
|
+
|
25
|
+
sage: from sage.misc.inline_fortran import _import_module_from_path
|
26
|
+
sage: modname = '___test__import_module_from_path'
|
27
|
+
sage: tmpdir = tmp_dir()
|
28
|
+
sage: filename = os.path.join(tmpdir, modname + '.py')
|
29
|
+
sage: with open(filename, 'w') as fobj:
|
30
|
+
....: _ = fobj.write('foo = "bar"')
|
31
|
+
sage: mod = _import_module_from_path(modname)
|
32
|
+
Traceback (most recent call last):
|
33
|
+
...
|
34
|
+
ImportError: No module named ___test__import_module_from_path
|
35
|
+
sage: mod = _import_module_from_path('DoEsNoTeXiSt', path=[tmpdir])
|
36
|
+
Traceback (most recent call last):
|
37
|
+
...
|
38
|
+
ImportError: No module named DoEsNoTeXiSt
|
39
|
+
sage: mod = _import_module_from_path(modname, path=[tmpdir])
|
40
|
+
sage: mod.foo
|
41
|
+
'bar'
|
42
|
+
"""
|
43
|
+
|
44
|
+
if path is None:
|
45
|
+
path = sys.path
|
46
|
+
|
47
|
+
return _import_module_from_path_impl(name, path)
|
48
|
+
|
49
|
+
|
50
|
+
def _import_module_from_path_impl(name, path):
|
51
|
+
"""Implement ``_import_module_from_path`` for Python 3.4+."""
|
52
|
+
|
53
|
+
# This is remarkably tricky to do right, considering that the new
|
54
|
+
# importlib is supposed to make direct interaction with the import
|
55
|
+
# system easier. I blame the ModuleSpec stuff...
|
56
|
+
finder = importlib.machinery.PathFinder()
|
57
|
+
spec = finder.find_spec(name, path=path)
|
58
|
+
if spec is None:
|
59
|
+
raise ImportError('No module named {}'.format(name))
|
60
|
+
mod = importlib.util.module_from_spec(spec)
|
61
|
+
spec.loader.exec_module(mod)
|
62
|
+
return mod
|
63
|
+
|
64
|
+
|
65
|
+
class InlineFortran:
|
66
|
+
def __init__(self, globals=None):
|
67
|
+
# globals=None means: use user globals from REPL
|
68
|
+
self.globs = globals
|
69
|
+
self.library_paths = []
|
70
|
+
self.libraries = []
|
71
|
+
self.verbose = False
|
72
|
+
|
73
|
+
def __repr__(self):
|
74
|
+
return "Interface to Fortran compiler"
|
75
|
+
|
76
|
+
def __call__(self, *args, **kwds):
|
77
|
+
return self.eval(*args, **kwds)
|
78
|
+
|
79
|
+
def eval(self, x, globals=None, locals=None):
|
80
|
+
"""
|
81
|
+
Compile fortran code ``x`` and adds the functions in it to ``globals``.
|
82
|
+
|
83
|
+
INPUT:
|
84
|
+
|
85
|
+
- ``x`` -- fortran code
|
86
|
+
|
87
|
+
- ``globals`` -- dictionary to which to add the functions from the
|
88
|
+
fortran module
|
89
|
+
|
90
|
+
- ``locals`` -- ignored
|
91
|
+
|
92
|
+
EXAMPLES::
|
93
|
+
|
94
|
+
sage: # needs numpy
|
95
|
+
sage: code = '''
|
96
|
+
....: C FILE: FIB1.F
|
97
|
+
....: SUBROUTINE FIB(A,N)
|
98
|
+
....: C
|
99
|
+
....: C CALCULATE FIRST N FIBONACCI NUMBERS
|
100
|
+
....: C
|
101
|
+
....: INTEGER N
|
102
|
+
....: REAL*8 A(N)
|
103
|
+
....: DO I=1,N
|
104
|
+
....: IF (I.EQ.1) THEN
|
105
|
+
....: A(I) = 0.0D0
|
106
|
+
....: ELSEIF (I.EQ.2) THEN
|
107
|
+
....: A(I) = 1.0D0
|
108
|
+
....: ELSE
|
109
|
+
....: A(I) = A(I-1) + A(I-2)
|
110
|
+
....: ENDIF
|
111
|
+
....: ENDDO
|
112
|
+
....: END
|
113
|
+
....: C END FILE FIB1.F
|
114
|
+
....: '''
|
115
|
+
sage: fortran(code, globals())
|
116
|
+
sage: import numpy
|
117
|
+
sage: a = numpy.array(range(10), dtype=float)
|
118
|
+
sage: fib(a, 10)
|
119
|
+
sage: a
|
120
|
+
array([ 0., 1., 1., 2., 3., 5., 8., 13., 21., 34.])
|
121
|
+
|
122
|
+
TESTS::
|
123
|
+
|
124
|
+
sage: os.chdir(DOT_SAGE)
|
125
|
+
sage: fortran.eval("SYNTAX ERROR !@#$")
|
126
|
+
Traceback (most recent call last):
|
127
|
+
...
|
128
|
+
RuntimeError: failed to compile Fortran code:...
|
129
|
+
sage: os.getcwd() == os.path.realpath(DOT_SAGE)
|
130
|
+
True
|
131
|
+
"""
|
132
|
+
if globals is None:
|
133
|
+
globals = self.globs
|
134
|
+
if globals is None:
|
135
|
+
from sage.repl.user_globals import get_globals
|
136
|
+
globals = get_globals()
|
137
|
+
|
138
|
+
# Create everything in a temporary directory
|
139
|
+
mytmpdir = tmp_dir()
|
140
|
+
|
141
|
+
try:
|
142
|
+
old_cwd = os.getcwd()
|
143
|
+
os.chdir(mytmpdir)
|
144
|
+
|
145
|
+
name = "fortran_module" # Python module name
|
146
|
+
# if the first line has !f90 as a comment, gfortran will
|
147
|
+
# treat it as Fortran 90 code
|
148
|
+
if x.startswith('!f90'):
|
149
|
+
fortran_file = name + '.f90'
|
150
|
+
else:
|
151
|
+
fortran_file = name + '.f'
|
152
|
+
|
153
|
+
s_lib_path = ['-L' + p for p in self.library_paths]
|
154
|
+
s_lib = ['-l' + l for l in self.libraries]
|
155
|
+
|
156
|
+
with open(fortran_file, 'w') as fobj:
|
157
|
+
fobj.write(x)
|
158
|
+
|
159
|
+
# This is basically the same as what f2py.compile() does, but we
|
160
|
+
# do it manually here in order to customize running the subprocess
|
161
|
+
# a bit more (in particular to capture stderr)
|
162
|
+
cmd = [sys.executable, '-c', 'import numpy.f2py; numpy.f2py.main()']
|
163
|
+
|
164
|
+
# What follows are the arguments to f2py itself (appended later
|
165
|
+
# just for logical separation)
|
166
|
+
cmd += ['-c', '-m', name, fortran_file, '--quiet',
|
167
|
+
'--f77exec=sage-inline-fortran',
|
168
|
+
'--f90exec=sage-inline-fortran'] + s_lib_path + s_lib
|
169
|
+
|
170
|
+
try:
|
171
|
+
out = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
|
172
|
+
except subprocess.CalledProcessError as exc:
|
173
|
+
raise RuntimeError(
|
174
|
+
"failed to compile Fortran code:\n{}".format(exc.output))
|
175
|
+
|
176
|
+
# Note that f2py() doesn't raise an exception if it fails.
|
177
|
+
# In that case, the import below will fail.
|
178
|
+
try:
|
179
|
+
mod = _import_module_from_path(name, [mytmpdir])
|
180
|
+
except ImportError as exc:
|
181
|
+
# Failed to import the module; include any output from building
|
182
|
+
# the module (even though it was ostensibly successful) in case
|
183
|
+
# it might help
|
184
|
+
msg = "failed to load compiled Fortran code: {}".format(exc)
|
185
|
+
if out:
|
186
|
+
msg += '\n' + out
|
187
|
+
raise RuntimeError(msg)
|
188
|
+
|
189
|
+
if self.verbose:
|
190
|
+
print(out)
|
191
|
+
finally:
|
192
|
+
os.chdir(old_cwd)
|
193
|
+
|
194
|
+
try:
|
195
|
+
shutil.rmtree(mytmpdir)
|
196
|
+
except OSError:
|
197
|
+
# This can fail for example over NFS
|
198
|
+
pass
|
199
|
+
|
200
|
+
for k, x in mod.__dict__.items():
|
201
|
+
if k[0] != '_':
|
202
|
+
globals[k] = x
|
203
|
+
|
204
|
+
def add_library(self, s):
|
205
|
+
self.libraries.append(s)
|
206
|
+
|
207
|
+
def add_library_path(self, s):
|
208
|
+
self.library_paths.append(s)
|
209
|
+
|
210
|
+
|
211
|
+
# An instance
|
212
|
+
fortran = InlineFortran()
|
sage/misc/messaging.py
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
"""
|
3
|
+
Message delivery
|
4
|
+
|
5
|
+
Various interfaces to messaging services. Currently:
|
6
|
+
|
7
|
+
- ``pushover`` -- a platform for sending and receiving push notifications
|
8
|
+
|
9
|
+
is supported.
|
10
|
+
|
11
|
+
AUTHORS:
|
12
|
+
|
13
|
+
- Martin Albrecht (2012) - initial implementation
|
14
|
+
"""
|
15
|
+
|
16
|
+
import http.client as httplib
|
17
|
+
from urllib.parse import urlencode
|
18
|
+
from ssl import create_default_context as default_context
|
19
|
+
|
20
|
+
pushover_defaults = {"token": "Eql67F14ohOZJ0AtEBJJU7FiLAk8wK"}
|
21
|
+
|
22
|
+
|
23
|
+
def pushover(message, **kwds):
|
24
|
+
"""
|
25
|
+
Send a push notification with ``message`` to ``user`` using https://pushover.net/.
|
26
|
+
|
27
|
+
Pushover is a platform for sending and receiving push notifications. On the server side, it
|
28
|
+
provides an HTTP API for queueing messages to deliver to devices. On the device side, iOS and
|
29
|
+
Android clients receive those push notifications, show them to the user, and store them for
|
30
|
+
offline viewing.
|
31
|
+
|
32
|
+
An account on https://pushover.net is required and the Pushover app must be installed on your
|
33
|
+
phone for this function to be able to deliver messages to you.
|
34
|
+
|
35
|
+
INPUT:
|
36
|
+
|
37
|
+
- ``message`` -- your message
|
38
|
+
|
39
|
+
- ``user`` -- the user key (not e-mail address) of your user (or you), viewable when logged
|
40
|
+
into the Pushover dashboard. (default: ``None``)
|
41
|
+
|
42
|
+
- ``device`` -- your user's device identifier to send the message directly to that device,
|
43
|
+
rather than all of the user's devices (default: ``None``)
|
44
|
+
|
45
|
+
- ``title`` -- your message's title, otherwise uses your app's name (default: ``None``)
|
46
|
+
|
47
|
+
- ``url`` -- a supplementary URL to show with your message (default: ``None``)
|
48
|
+
|
49
|
+
- ``url_title`` -- a title for your supplementary URL (default: ``None``)
|
50
|
+
|
51
|
+
- ``priority`` -- set to 1 to display as high-priority and bypass quiet hours, or -1 to always
|
52
|
+
send as a quiet notification (default: ``0``)
|
53
|
+
|
54
|
+
- ``timestamp`` -- set to a unix timestamp to have your message show with a particular time,
|
55
|
+
rather than now (default: ``None``)
|
56
|
+
|
57
|
+
- ``sound`` -- set to the name of one of the sounds supported by device clients to override the
|
58
|
+
user's default sound choice (default: ``None``)
|
59
|
+
|
60
|
+
- ``token`` -- your application's API token (default: Sage's default App token)
|
61
|
+
|
62
|
+
EXAMPLES::
|
63
|
+
|
64
|
+
sage: import sage.misc.messaging
|
65
|
+
sage: sage.misc.messaging.pushover("Hi, how are you?", user="XXX") # not tested
|
66
|
+
|
67
|
+
To set default values populate ``pushover_defaults``::
|
68
|
+
|
69
|
+
sage: sage.misc.messaging.pushover_defaults["user"] = "USER_TOKEN"
|
70
|
+
sage: sage.misc.messaging.pushover("Hi, how are you?") # not tested
|
71
|
+
|
72
|
+
.. NOTE::
|
73
|
+
|
74
|
+
You may want to populate ``sage.misc.messaging.pushover_defaults`` with default values such
|
75
|
+
as the default user in ``$HOME/.sage/init.sage``.
|
76
|
+
"""
|
77
|
+
request = {"message": message}
|
78
|
+
request.update(pushover_defaults)
|
79
|
+
request.update(kwds)
|
80
|
+
|
81
|
+
conn = httplib.HTTPSConnection("api.pushover.net:443",
|
82
|
+
context=default_context())
|
83
|
+
conn.request("POST", "/1/messages.json",
|
84
|
+
urlencode(request),
|
85
|
+
{"Content-type": "application/x-www-form-urlencoded"})
|
86
|
+
return conn.getresponse().status == 200
|
sage/misc/pager.py
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
"""
|
3
|
+
Pager for showing strings
|
4
|
+
|
5
|
+
Currently we just use the IPython pager.
|
6
|
+
If we want to use something else, we can just change this function.
|
7
|
+
|
8
|
+
Any code in sage that uses a pager should use this pager.
|
9
|
+
"""
|
10
|
+
# ---------------------------------------------------------------------------
|
11
|
+
# Copyright (C) 2006 William Stein <wstein@gmail.com>
|
12
|
+
#
|
13
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
14
|
+
#
|
15
|
+
# https://www.gnu.org/licenses/
|
16
|
+
# ---------------------------------------------------------------------------
|
17
|
+
|
18
|
+
|
19
|
+
def pager():
|
20
|
+
import IPython.core.page
|
21
|
+
return IPython.core.page.page
|