passagemath-repl 10.5.1__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.5.1.data/scripts/sage-cachegrind +25 -0
  2. passagemath_repl-10.5.1.data/scripts/sage-callgrind +16 -0
  3. passagemath_repl-10.5.1.data/scripts/sage-cleaner +230 -0
  4. passagemath_repl-10.5.1.data/scripts/sage-coverage +327 -0
  5. passagemath_repl-10.5.1.data/scripts/sage-eval +14 -0
  6. passagemath_repl-10.5.1.data/scripts/sage-fixdoctests +710 -0
  7. passagemath_repl-10.5.1.data/scripts/sage-inline-fortran +12 -0
  8. passagemath_repl-10.5.1.data/scripts/sage-ipynb2rst +50 -0
  9. passagemath_repl-10.5.1.data/scripts/sage-ipython +16 -0
  10. passagemath_repl-10.5.1.data/scripts/sage-massif +25 -0
  11. passagemath_repl-10.5.1.data/scripts/sage-notebook +267 -0
  12. passagemath_repl-10.5.1.data/scripts/sage-omega +25 -0
  13. passagemath_repl-10.5.1.data/scripts/sage-preparse +302 -0
  14. passagemath_repl-10.5.1.data/scripts/sage-run +27 -0
  15. passagemath_repl-10.5.1.data/scripts/sage-run-cython +10 -0
  16. passagemath_repl-10.5.1.data/scripts/sage-runtests +9 -0
  17. passagemath_repl-10.5.1.data/scripts/sage-startuptime.py +163 -0
  18. passagemath_repl-10.5.1.data/scripts/sage-valgrind +34 -0
  19. passagemath_repl-10.5.1.dist-info/METADATA +77 -0
  20. passagemath_repl-10.5.1.dist-info/RECORD +162 -0
  21. passagemath_repl-10.5.1.dist-info/WHEEL +5 -0
  22. passagemath_repl-10.5.1.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 +134 -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 +249 -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/all.py +0 -0
  143. sage/tests/all__sagemath_repl.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 +1925 -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 +796 -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/doctest/util.py ADDED
@@ -0,0 +1,750 @@
1
+ # sage_setup: distribution = sagemath-repl
2
+ """
3
+ Utility functions
4
+
5
+ This module contains various utility functions and classes used in doctesting.
6
+
7
+ AUTHORS:
8
+
9
+ - David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code.
10
+ """
11
+
12
+ # ****************************************************************************
13
+ # Copyright (C) 2012 David Roe <roed.math@gmail.com>
14
+ # 2012 Robert Bradshaw <robertwb@gmail.com>
15
+ # 2012 William Stein <wstein@gmail.com>
16
+ # 2013 Jeroen Demeyer <jdemeyer@cage.ugent.be>
17
+ # 2014 Volker Braun
18
+ # 2017 Frédéric Chapoton
19
+ #
20
+ # Distributed under the terms of the GNU General Public License (GPL)
21
+ # as published by the Free Software Foundation; either version 2 of
22
+ # the License, or (at your option) any later version.
23
+ # https://www.gnu.org/licenses/
24
+ # ****************************************************************************
25
+
26
+ from time import time as walltime
27
+ from os import sysconf, times
28
+
29
+ def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False):
30
+ """
31
+ EXAMPLES::
32
+
33
+ sage: from sage.doctest.util import count_noun
34
+ sage: count_noun(1, "apple")
35
+ '1 apple'
36
+ sage: count_noun(1, "apple", pad_noun=True)
37
+ '1 apple '
38
+ sage: count_noun(1, "apple", pad_number=3)
39
+ ' 1 apple'
40
+ sage: count_noun(2, "orange")
41
+ '2 oranges'
42
+ sage: count_noun(3, "peach", "peaches")
43
+ '3 peaches'
44
+ sage: count_noun(1, "peach", plural='peaches', pad_noun=True)
45
+ '1 peach '
46
+ """
47
+ if plural is None:
48
+ plural = noun + "s"
49
+ if pad_noun:
50
+ # We assume that the plural is never shorter than the noun....
51
+ pad_noun = " " * (len(plural) - len(noun))
52
+ else:
53
+ pad_noun = ""
54
+ if pad_number:
55
+ number_str = ("%%%sd" % pad_number) % number
56
+ else:
57
+ number_str = "%d" % number
58
+ if number == 1:
59
+ return "%s %s%s" % (number_str, noun, pad_noun)
60
+ else:
61
+ return "%s %s" % (number_str, plural)
62
+
63
+
64
+ def dict_difference(self, other):
65
+ """
66
+ Return a dict with all key-value pairs occurring in ``self`` but not
67
+ in ``other``.
68
+
69
+ EXAMPLES::
70
+
71
+ sage: from sage.doctest.util import dict_difference
72
+ sage: d1 = {1: 'a', 2: 'b', 3: 'c'}
73
+ sage: d2 = {1: 'a', 2: 'x', 4: 'c'}
74
+ sage: dict_difference(d2, d1)
75
+ {2: 'x', 4: 'c'}
76
+
77
+ ::
78
+
79
+ sage: from sage.doctest.control import DocTestDefaults
80
+ sage: D1 = DocTestDefaults()
81
+ sage: D2 = DocTestDefaults(foobar='hello', timeout=100)
82
+ sage: dict_difference(D2.__dict__, D1.__dict__)
83
+ {'foobar': 'hello', 'timeout': 100}
84
+ """
85
+ D = {}
86
+ for k, v in self.items():
87
+ try:
88
+ if other[k] == v:
89
+ continue
90
+ except KeyError:
91
+ pass
92
+ D[k] = v
93
+ return D
94
+
95
+
96
+ class Timer:
97
+ """
98
+ A simple timer.
99
+
100
+ EXAMPLES::
101
+
102
+ sage: from sage.doctest.util import Timer
103
+ sage: Timer()
104
+ {}
105
+ sage: TestSuite(Timer()).run()
106
+ """
107
+
108
+ def _proc_stat_cpu_seconds(self, path):
109
+ r"""
110
+ Parse a "stat" file from the ``/proc`` filesystem to get
111
+ the cputime of a process.
112
+
113
+ This also includes the times for child processes, but only
114
+ those that have already terminated and for which ``wait()``
115
+ was called. It is important to note that pexpect processes DO
116
+ NOT fall into that category.
117
+
118
+ The document ``Documentation/filesystems/proc.rst`` within the
119
+ Linux kernel source tree defines a "stat" file.
120
+
121
+ INPUT:
122
+
123
+ - ``path`` -- string; the path to a "stat" file on the ``/proc``
124
+ filesystem, typically "/proc/<pid>/stat", from which we will
125
+ read cputime information
126
+
127
+ OUTPUT:
128
+
129
+ A nonnegative float representing the number of cpu-seconds
130
+ used by the process associated with ``path``. An ``OSError`` is
131
+ raised if anything goes wrong, which typically happens on
132
+ platforms that don't store this information under ``/proc``.
133
+
134
+ TESTS:
135
+
136
+ About all we can say for certain is that this will return a
137
+ nonnegative float or raise an ``OSError``::
138
+
139
+ sage: from sage.doctest.util import Timer
140
+ sage: cputime = float(0.0)
141
+ sage: path = "/proc/1/stat"
142
+ sage: try:
143
+ ....: cputime = Timer()._proc_stat_cpu_seconds(path)
144
+ ....: except OSError:
145
+ ....: pass
146
+ sage: cputime >= 0.0
147
+ True
148
+ sage: isinstance(cputime, float)
149
+ True
150
+
151
+ We can force an ``OSError`` with an invalid PID::
152
+
153
+ sage: from sage.doctest.util import Timer
154
+ sage: path = "/proc/-1/stat"
155
+ sage: cputime = Timer()._proc_stat_cpu_seconds(path)
156
+ Traceback (most recent call last):
157
+ ...
158
+ OSError: unable to access /proc/-1/stat
159
+
160
+ Or with an unparseable file (wrong number of fields, non-float
161
+ fields, et cetera)::
162
+
163
+ sage: from tempfile import NamedTemporaryFile
164
+ sage: from os import unlink
165
+ sage: from sage.doctest.util import Timer
166
+ sage: with NamedTemporaryFile(delete=False, mode="w") as f:
167
+ ....: _ = f.write("1 2 3 4 5")
168
+ sage: cputime = Timer()._proc_stat_cpu_seconds(f.name)
169
+ Traceback (most recent call last):
170
+ ...
171
+ OSError: unable to parse ...
172
+ sage: os.unlink(f.name)
173
+ sage: with NamedTemporaryFile(delete=False, mode="w") as f:
174
+ ....: _ = f.write("1 2 3 4 5 6 7 8 9 10 11 12 w x y z 17")
175
+ sage: cputime = Timer()._proc_stat_cpu_seconds(f.name)
176
+ Traceback (most recent call last):
177
+ ...
178
+ OSError: unable to parse ...
179
+ sage: os.unlink(f.name)
180
+
181
+ """
182
+ try:
183
+ with open(path, "r") as statfile:
184
+ stats = statfile.read().split()
185
+ except (FileNotFoundError, PermissionError) as e:
186
+ # FileNotFoundError: bad PID, or no /proc support
187
+ # PermissionError: can't read the stat file
188
+ raise OSError(f"unable to access {path}") from e
189
+
190
+ if len(stats) < 17:
191
+ raise OSError(f"unable to parse {path}")
192
+
193
+ try:
194
+ # These fields used to be documented in the proc(5) man
195
+ # page, but are now most easily found in the Linux kernel
196
+ # documentation (Documentation/filesystems/proc.rst). The
197
+ # intent is to sum the user- and kernel-mode "jiffies" for
198
+ # both the given process and its children.
199
+ cputicks = sum( float(s) for s in stats[13:17] )
200
+ except (ArithmeticError, TypeError, ValueError) as e:
201
+ # ArithmeticError: unexpected (non-numeric?) values in fields
202
+ # TypeError/ValueError: fields can't be converted to float
203
+ raise OSError(f"unable to parse {path}") from e
204
+
205
+ try:
206
+ hertz = sysconf("SC_CLK_TCK")
207
+ except (ValueError) as e:
208
+ # ValueError: SC_CLK_TCK doesn't exist
209
+ raise OSError("SC_CLK_TCK sysconf not found") from e
210
+
211
+ if hertz <= 0:
212
+ # The python documentation for os.sysconf() says, "If the
213
+ # configuration value specified by name isn’t defined, -1
214
+ # is returned." Having tried this with a junk value, I
215
+ # don't believe it: I got a ValueError that was handled
216
+ # above. Nevertheless, we play it safe here and turn a -1
217
+ # into an OSError. We check for zero, too, because we're
218
+ # about to divide by it.
219
+ raise OSError("SC_CLK_TCK sysconf is nonpositive")
220
+
221
+ return (cputicks / hertz)
222
+
223
+ def _quick_cputime(self, expect_objects):
224
+ r"""
225
+ A fast replacement for ``sage.misc.timing.cputime``.
226
+
227
+ This is a "reliable" replacement (on Linux/BSD) that takes
228
+ subprocesses (particularly pexpect interfaces) into
229
+ account. The ``cputime()`` function from the ``misc`` module
230
+ can be passed ``subprocesses=True``, but this has a few
231
+ faults; mainly that it relies on each pexpect interface to
232
+ implement its own ``cputime()`` function. And most of our
233
+ pexpect interfaces either don't implement one, or implement
234
+ one in a way that requires the subprocess (being pexpected) to
235
+ be in perfect working condition -- that will often not be the
236
+ case at the end of a doctest line.
237
+
238
+ INPUT:
239
+
240
+ - ``expect_objects`` -- list; a list of
241
+ :class:`sage.interfaces.expect.Expect` instances whose CPU
242
+ times will be included in the total
243
+
244
+ OUTPUT:
245
+
246
+ A float measuring the cputime in seconds of the sage process
247
+ and all its subprocesses.
248
+
249
+ TESTS:
250
+
251
+ About all we can say for certain is that this will return a
252
+ nonnegative float::
253
+
254
+ sage: from sage.doctest.util import Timer
255
+ sage: from sage.interfaces.quit import expect_objects
256
+ sage: cputime = Timer()._quick_cputime(expect_objects)
257
+ sage: cputime >= 0.0
258
+ True
259
+ sage: isinstance(cputime, float)
260
+ True
261
+
262
+ If an error occurs in :meth:`_proc_stat_cpu_seconds`, this
263
+ function should still return a valid answer, albeit one that
264
+ is missing timing information for the PID that failed::
265
+
266
+ sage: class FakeExpect:
267
+ ....: def __call__(self):
268
+ ....: return self
269
+ ....: def is_running(self):
270
+ ....: return True
271
+ ....: def pid(self):
272
+ ....: return -1
273
+ sage: e = FakeExpect()
274
+ sage: from sage.doctest.util import Timer
275
+ sage: cputime = Timer()._quick_cputime([e])
276
+ sage: cputime >= 0.0
277
+ True
278
+ sage: isinstance(cputime, float)
279
+ True
280
+ """
281
+ # Start by using os.times() to get the cputime for sage itself
282
+ # and any subprocesses that have been wait()ed for and that
283
+ # have terminated.
284
+ cputime = sum( times()[:4] )
285
+
286
+ # Now try to get the times for any pexpect interfaces, since
287
+ # they do not fall into the category above.
288
+ for s in expect_objects:
289
+ S = s()
290
+ if S and S.is_running():
291
+ try:
292
+ # This will fail anywhere but linux/BSD, but
293
+ # there's no good cross-platform way to get the
294
+ # cputimes from pexpect interfaces without totally
295
+ # mucking up the doctests.
296
+ path = f"/proc/{S.pid()}/stat"
297
+ cputime += self._proc_stat_cpu_seconds(path)
298
+ except OSError:
299
+ # If we're on macOS, we can fall back to using
300
+ # psutil, but only if it's installed. It's usually
301
+ # installed as a transitive dependency (ipython
302
+ # needs it), but it isn't explicitly listed as
303
+ # a dependency of sagelib.
304
+ try:
305
+ from psutil import (NoSuchProcess,
306
+ Process,
307
+ ZombieProcess)
308
+ try:
309
+ cputime += sum(Process(S.pid()).cpu_times()[0:2])
310
+ except (ValueError, NoSuchProcess, ZombieProcess):
311
+ # ValueError: invalid (e.g. negative) PID
312
+ # NoSuchProcess: it's gone
313
+ # ZombieProcess: PID refers to a zombie
314
+ pass
315
+ except ImportError:
316
+ pass
317
+
318
+ return cputime
319
+
320
+ def start(self):
321
+ """
322
+ Start the timer.
323
+
324
+ Can be called multiple times to reset the timer.
325
+
326
+ EXAMPLES::
327
+
328
+ sage: from sage.doctest.util import Timer
329
+ sage: Timer().start()
330
+ {'cputime': ..., 'walltime': ...}
331
+ """
332
+ from sage.interfaces.quit import expect_objects
333
+ self.cputime = self._quick_cputime(expect_objects)
334
+ self.walltime = walltime()
335
+ return self
336
+
337
+ def stop(self):
338
+ """
339
+ Stops the timer, recording the time that has passed since it
340
+ was started.
341
+
342
+ EXAMPLES::
343
+
344
+ sage: from sage.doctest.util import Timer
345
+ sage: import time
346
+ sage: timer = Timer().start()
347
+ sage: time.sleep(float(0.5))
348
+ sage: timer.stop()
349
+ {'cputime': ..., 'walltime': ...}
350
+ """
351
+ from sage.interfaces.quit import expect_objects
352
+ self.cputime = self._quick_cputime(expect_objects) - self.cputime
353
+ self.walltime = walltime() - self.walltime
354
+ return self
355
+
356
+ def annotate(self, object):
357
+ """
358
+ Annotates the given object with the cputime and walltime
359
+ stored in this timer.
360
+
361
+ EXAMPLES::
362
+
363
+ sage: # needs sage.schemes
364
+ sage: from sage.doctest.util import Timer
365
+ sage: Timer().start().annotate(EllipticCurve) # needs sage.schemes
366
+ sage: EllipticCurve.cputime # random # needs sage.schemes
367
+ 2.817255
368
+ sage: EllipticCurve.walltime # random # needs sage.schemes
369
+ 1332649288.410404
370
+ """
371
+ object.cputime = self.cputime
372
+ object.walltime = self.walltime
373
+
374
+ def __repr__(self):
375
+ """
376
+ String representation is from the dictionary.
377
+
378
+ EXAMPLES::
379
+
380
+ sage: from sage.doctest.util import Timer
381
+ sage: repr(Timer().start()) # indirect doctest
382
+ "{'cputime': ..., 'walltime': ...}"
383
+ """
384
+ return str(self)
385
+
386
+ def __str__(self):
387
+ """
388
+ String representation is from the dictionary.
389
+
390
+ EXAMPLES::
391
+
392
+ sage: from sage.doctest.util import Timer
393
+ sage: str(Timer().start()) # indirect doctest
394
+ "{'cputime': ..., 'walltime': ...}"
395
+ """
396
+ return str(self.__dict__)
397
+
398
+ def __eq__(self, other):
399
+ """
400
+ Comparison.
401
+
402
+ EXAMPLES::
403
+
404
+ sage: from sage.doctest.util import Timer
405
+ sage: Timer() == Timer()
406
+ True
407
+ sage: t = Timer().start()
408
+ sage: loads(dumps(t)) == t
409
+ True
410
+ """
411
+ if not isinstance(other, Timer):
412
+ return False
413
+ return self.__dict__ == other.__dict__
414
+
415
+ def __ne__(self, other):
416
+ """
417
+ Test for non-equality.
418
+
419
+ EXAMPLES::
420
+
421
+ sage: from sage.doctest.util import Timer
422
+ sage: Timer() == Timer()
423
+ True
424
+ sage: t = Timer().start()
425
+ sage: loads(dumps(t)) != t
426
+ False
427
+ """
428
+ return not (self == other)
429
+
430
+
431
+ # Inheritance rather then delegation as globals() must be a dict
432
+ class RecordingDict(dict):
433
+ """
434
+ This dictionary is used for tracking the dependencies of an example.
435
+
436
+ This feature allows examples in different doctests to be grouped
437
+ for better timing data. It's obtained by recording whenever
438
+ anything is set or retrieved from this dictionary.
439
+
440
+ EXAMPLES::
441
+
442
+ sage: from sage.doctest.util import RecordingDict
443
+ sage: D = RecordingDict(test=17)
444
+ sage: D.got
445
+ set()
446
+ sage: D['test']
447
+ 17
448
+ sage: D.got
449
+ {'test'}
450
+ sage: D.set
451
+ set()
452
+ sage: D['a'] = 1
453
+ sage: D['a']
454
+ 1
455
+ sage: D.set
456
+ {'a'}
457
+ sage: D.got
458
+ {'test'}
459
+
460
+ TESTS::
461
+
462
+ sage: TestSuite(D).run()
463
+ """
464
+ def __init__(self, *args, **kwds):
465
+ """
466
+ Initialization arguments are the same as for a normal dictionary.
467
+
468
+ EXAMPLES::
469
+
470
+ sage: from sage.doctest.util import RecordingDict
471
+ sage: D = RecordingDict(d = 42)
472
+ sage: D.got
473
+ set()
474
+ """
475
+ dict.__init__(self, *args, **kwds)
476
+ self.start()
477
+
478
+ def start(self):
479
+ """
480
+ We track which variables have been set or retrieved.
481
+ This function initializes these lists to be empty.
482
+
483
+ EXAMPLES::
484
+
485
+ sage: from sage.doctest.util import RecordingDict
486
+ sage: D = RecordingDict(d = 42)
487
+ sage: D.set
488
+ set()
489
+ sage: D['a'] = 4
490
+ sage: D.set
491
+ {'a'}
492
+ sage: D.start(); D.set
493
+ set()
494
+ """
495
+ self.set = set()
496
+ self.got = set()
497
+
498
+ def __getitem__(self, name):
499
+ """
500
+ EXAMPLES::
501
+
502
+ sage: from sage.doctest.util import RecordingDict
503
+ sage: D = RecordingDict(d = 42)
504
+ sage: D['a'] = 4
505
+ sage: D.got
506
+ set()
507
+ sage: D['a'] # indirect doctest
508
+ 4
509
+ sage: D.got
510
+ set()
511
+ sage: D['d']
512
+ 42
513
+ sage: D.got
514
+ {'d'}
515
+ """
516
+ if name not in self.set:
517
+ self.got.add(name)
518
+ return dict.__getitem__(self, name)
519
+
520
+ def __setitem__(self, name, value):
521
+ """
522
+ EXAMPLES::
523
+
524
+ sage: from sage.doctest.util import RecordingDict
525
+ sage: D = RecordingDict(d = 42)
526
+ sage: D['a'] = 4 # indirect doctest
527
+ sage: D.set
528
+ {'a'}
529
+ """
530
+ self.set.add(name)
531
+ dict.__setitem__(self, name, value)
532
+
533
+ def __delitem__(self, name):
534
+ """
535
+ EXAMPLES::
536
+
537
+ sage: from sage.doctest.util import RecordingDict
538
+ sage: D = RecordingDict(d = 42)
539
+ sage: del D['d'] # indirect doctest
540
+ sage: D.set
541
+ {'d'}
542
+ """
543
+ self.set.add(name)
544
+ dict.__delitem__(self, name)
545
+
546
+ def get(self, name, default=None):
547
+ """
548
+ EXAMPLES::
549
+
550
+ sage: from sage.doctest.util import RecordingDict
551
+ sage: D = RecordingDict(d = 42)
552
+ sage: D.get('d')
553
+ 42
554
+ sage: D.got
555
+ {'d'}
556
+ sage: D.get('not_here')
557
+ sage: sorted(list(D.got))
558
+ ['d', 'not_here']
559
+ """
560
+ if name not in self.set:
561
+ self.got.add(name)
562
+ return dict.get(self, name, default)
563
+
564
+ def copy(self):
565
+ """
566
+ Note that set and got are not copied.
567
+
568
+ EXAMPLES::
569
+
570
+ sage: from sage.doctest.util import RecordingDict
571
+ sage: D = RecordingDict(d = 42)
572
+ sage: D['a'] = 4
573
+ sage: D.set
574
+ {'a'}
575
+ sage: E = D.copy()
576
+ sage: E.set
577
+ set()
578
+ sage: sorted(E.keys())
579
+ ['a', 'd']
580
+ """
581
+ return RecordingDict(dict.copy(self))
582
+
583
+ def __reduce__(self):
584
+ """
585
+ Pickling.
586
+
587
+ EXAMPLES::
588
+
589
+ sage: from sage.doctest.util import RecordingDict
590
+ sage: D = RecordingDict(d = 42)
591
+ sage: D['a'] = 4
592
+ sage: D.get('not_here')
593
+ sage: E = loads(dumps(D))
594
+ sage: E.got
595
+ {'not_here'}
596
+ """
597
+ return make_recording_dict, (dict(self), self.set, self.got)
598
+
599
+
600
+ def make_recording_dict(D, st, gt):
601
+ """
602
+ Auxiliary function for pickling.
603
+
604
+ EXAMPLES::
605
+
606
+ sage: from sage.doctest.util import make_recording_dict
607
+ sage: D = make_recording_dict({'a':4,'d':42},set([]),set(['not_here']))
608
+ sage: sorted(D.items())
609
+ [('a', 4), ('d', 42)]
610
+ sage: D.got
611
+ {'not_here'}
612
+ """
613
+ ans = RecordingDict(D)
614
+ ans.set = st
615
+ ans.got = gt
616
+ return ans
617
+
618
+ class NestedName:
619
+ """
620
+ Class used to construct fully qualified names based on indentation level.
621
+
622
+ EXAMPLES::
623
+
624
+ sage: from sage.doctest.util import NestedName
625
+ sage: qname = NestedName('sage.categories.algebras')
626
+ sage: qname[0] = 'Algebras'; qname
627
+ sage.categories.algebras.Algebras
628
+ sage: qname[4] = '__contains__'; qname
629
+ sage.categories.algebras.Algebras.__contains__
630
+ sage: qname[4] = 'ParentMethods'
631
+ sage: qname[8] = 'from_base_ring'; qname
632
+ sage.categories.algebras.Algebras.ParentMethods.from_base_ring
633
+
634
+ TESTS::
635
+
636
+ sage: TestSuite(qname).run()
637
+ """
638
+ def __init__(self, base):
639
+ """
640
+ INPUT:
641
+
642
+ - ``base`` -- string; the name of the module
643
+
644
+ EXAMPLES::
645
+
646
+ sage: from sage.doctest.util import NestedName
647
+ sage: qname = NestedName('sage.categories.algebras')
648
+ sage: qname
649
+ sage.categories.algebras
650
+ """
651
+ self.all = [base]
652
+
653
+ def __setitem__(self, index, value):
654
+ """
655
+ Set the value at a given indentation level.
656
+
657
+ INPUT:
658
+
659
+ - ``index`` -- positive integer; the indentation level (often a
660
+ multiple of 4, but not necessarily)
661
+ - ``value`` -- string; the name of the class or function at that
662
+ indentation level
663
+
664
+ EXAMPLES::
665
+
666
+ sage: from sage.doctest.util import NestedName
667
+ sage: qname = NestedName('sage.categories.algebras')
668
+ sage: qname[1] = 'Algebras' # indirect doctest
669
+ sage: qname
670
+ sage.categories.algebras.Algebras
671
+ sage: qname.all
672
+ ['sage.categories.algebras', None, 'Algebras']
673
+ """
674
+ if index < 0:
675
+ raise ValueError
676
+ while len(self.all) <= index:
677
+ self.all.append(None)
678
+ self.all[index+1:] = [value]
679
+
680
+ def __str__(self):
681
+ """
682
+ Return a .-separated string giving the full name.
683
+
684
+ EXAMPLES::
685
+
686
+ sage: from sage.doctest.util import NestedName
687
+ sage: qname = NestedName('sage.categories.algebras')
688
+ sage: qname[1] = 'Algebras'
689
+ sage: qname[44] = 'at_the_end_of_the_universe'
690
+ sage: str(qname) # indirect doctest
691
+ 'sage.categories.algebras.Algebras.at_the_end_of_the_universe'
692
+ """
693
+ return repr(self)
694
+
695
+ def __repr__(self):
696
+ """
697
+ Return a .-separated string giving the full name.
698
+
699
+ EXAMPLES::
700
+
701
+ sage: from sage.doctest.util import NestedName
702
+ sage: qname = NestedName('sage.categories.algebras')
703
+ sage: qname[1] = 'Algebras'
704
+ sage: qname[44] = 'at_the_end_of_the_universe'
705
+ sage: print(qname) # indirect doctest
706
+ sage.categories.algebras.Algebras.at_the_end_of_the_universe
707
+ """
708
+ return '.'.join(a for a in self.all if a is not None)
709
+
710
+ def __eq__(self, other):
711
+ """
712
+ Comparison is just comparison of the underlying lists.
713
+
714
+ EXAMPLES::
715
+
716
+ sage: from sage.doctest.util import NestedName
717
+ sage: qname = NestedName('sage.categories.algebras')
718
+ sage: qname2 = NestedName('sage.categories.algebras')
719
+ sage: qname == qname2
720
+ True
721
+ sage: qname[0] = 'Algebras'
722
+ sage: qname2[2] = 'Algebras'
723
+ sage: repr(qname) == repr(qname2)
724
+ True
725
+ sage: qname == qname2
726
+ False
727
+ """
728
+ if not isinstance(other, NestedName):
729
+ return False
730
+ return self.all == other.all
731
+
732
+ def __ne__(self, other):
733
+ """
734
+ Test for non-equality.
735
+
736
+ EXAMPLES::
737
+
738
+ sage: from sage.doctest.util import NestedName
739
+ sage: qname = NestedName('sage.categories.algebras')
740
+ sage: qname2 = NestedName('sage.categories.algebras')
741
+ sage: qname != qname2
742
+ False
743
+ sage: qname[0] = 'Algebras'
744
+ sage: qname2[2] = 'Algebras'
745
+ sage: repr(qname) == repr(qname2)
746
+ True
747
+ sage: qname != qname2
748
+ True
749
+ """
750
+ return not (self == other)