Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/doctest/util.py
8817 views
1
"""
2
Utility functions
3
4
This module contains various utility functions and classes used in doctesting.
5
6
AUTHORS:
7
8
- David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code.
9
"""
10
11
#*****************************************************************************
12
# Copyright (C) 2012 David Roe <[email protected]>
13
# Robert Bradshaw <[email protected]>
14
# William Stein <[email protected]>
15
#
16
# Distributed under the terms of the GNU General Public License (GPL)
17
# as published by the Free Software Foundation; either version 2 of
18
# the License, or (at your option) any later version.
19
# http://www.gnu.org/licenses/
20
#*****************************************************************************
21
22
23
from sage.misc.misc import walltime, cputime
24
25
def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False):
26
"""
27
EXAMPLES::
28
29
sage: from sage.doctest.util import count_noun
30
sage: count_noun(1, "apple")
31
'1 apple'
32
sage: count_noun(1, "apple", pad_noun=True)
33
'1 apple '
34
sage: count_noun(1, "apple", pad_number=3)
35
' 1 apple'
36
sage: count_noun(2, "orange")
37
'2 oranges'
38
sage: count_noun(3, "peach", "peaches")
39
'3 peaches'
40
sage: count_noun(1, "peach", plural="peaches", pad_noun=True)
41
'1 peach '
42
"""
43
if plural is None:
44
plural = noun + "s"
45
if pad_noun:
46
# We assume that the plural is never shorter than the noun....
47
pad_noun = " " * (len(plural) - len(noun))
48
else:
49
pad_noun = ""
50
if pad_number:
51
number_str = ("%%%sd"%pad_number)%number
52
else:
53
number_str = "%d"%number
54
if number == 1:
55
return "%s %s%s"%(number_str, noun, pad_noun)
56
else:
57
return "%s %s"%(number_str, plural)
58
59
60
def dict_difference(self, other):
61
"""
62
Return a dict with all key-value pairs occuring in ``self`` but not
63
in ``other``.
64
65
EXAMPLES::
66
67
sage: from sage.doctest.util import dict_difference
68
sage: d1 = {1: 'a', 2: 'b', 3: 'c'}
69
sage: d2 = {1: 'a', 2: 'x', 4: 'c'}
70
sage: dict_difference(d2, d1)
71
{2: 'x', 4: 'c'}
72
73
::
74
75
sage: from sage.doctest.control import DocTestDefaults
76
sage: D1 = DocTestDefaults()
77
sage: D2 = DocTestDefaults(foobar="hello", timeout=100)
78
sage: dict_difference(D2.__dict__, D1.__dict__)
79
{'foobar': 'hello', 'timeout': 100}
80
"""
81
D = dict()
82
for (k,v) in self.iteritems():
83
try:
84
if other[k] == v:
85
continue
86
except KeyError:
87
pass
88
D[k] = v
89
return D
90
91
92
class Timer:
93
"""
94
A simple timer.
95
96
EXAMPLES::
97
98
sage: from sage.doctest.util import Timer
99
sage: Timer()
100
{}
101
sage: TestSuite(Timer()).run()
102
"""
103
def start(self):
104
"""
105
Start the timer.
106
107
EXAMPLES::
108
109
sage: from sage.doctest.util import Timer
110
sage: Timer().start()
111
{'cputime': ..., 'walltime': ...}
112
"""
113
self.cputime = cputime()
114
self.walltime = walltime()
115
return self
116
117
def stop(self):
118
"""
119
Stops the timer, recording the time that has passed since it
120
was started.
121
122
EXAMPLES::
123
124
sage: from sage.doctest.util import Timer
125
sage: import time
126
sage: timer = Timer().start()
127
sage: time.sleep(0.5)
128
sage: timer.stop()
129
{'cputime': ..., 'walltime': ...}
130
"""
131
self.cputime = cputime(self.cputime)
132
self.walltime = walltime(self.walltime)
133
return self
134
135
def annotate(self, object):
136
"""
137
Annotates the given object with the cputime and walltime
138
stored in this timer.
139
140
EXAMPLES::
141
142
sage: from sage.doctest.util import Timer
143
sage: Timer().start().annotate(EllipticCurve)
144
sage: EllipticCurve.cputime # random
145
2.817255
146
sage: EllipticCurve.walltime # random
147
1332649288.410404
148
"""
149
object.cputime = self.cputime
150
object.walltime = self.walltime
151
152
def __repr__(self):
153
"""
154
String representation is from the dictionary.
155
156
EXAMPLES::
157
158
sage: from sage.doctest.util import Timer
159
sage: repr(Timer().start()) # indirect doctest
160
"{'cputime': ..., 'walltime': ...}"
161
"""
162
return str(self)
163
164
def __str__(self):
165
"""
166
String representation is from the dictionary.
167
168
EXAMPLES::
169
170
sage: from sage.doctest.util import Timer
171
sage: str(Timer().start()) # indirect doctest
172
"{'cputime': ..., 'walltime': ...}"
173
"""
174
return str(self.__dict__)
175
176
def __cmp__(self, other):
177
"""
178
Comparison.
179
180
EXAMPLES::
181
182
sage: from sage.doctest.util import Timer
183
sage: Timer() == Timer()
184
True
185
sage: t = Timer().start()
186
sage: loads(dumps(t)) == t
187
True
188
"""
189
c = cmp(type(self), type(other))
190
if c: return c
191
return cmp(self.__dict__, other.__dict__)
192
193
# Inheritance rather then delegation as globals() must be a dict
194
class RecordingDict(dict):
195
"""
196
This dictionary is used for tracking the dependencies of an example.
197
198
This feature allows examples in different doctests to be grouped
199
for better timing data. It's obtained by recording whenever
200
anything is set or retrieved from this dictionary.
201
202
EXAMPLES::
203
204
sage: from sage.doctest.util import RecordingDict
205
sage: D = RecordingDict(test=17)
206
sage: D.got
207
set([])
208
sage: D['test']
209
17
210
sage: D.got
211
set(['test'])
212
sage: D.set
213
set([])
214
sage: D['a'] = 1
215
sage: D['a']
216
1
217
sage: D.set
218
set(['a'])
219
sage: D.got
220
set(['test'])
221
222
TESTS::
223
224
sage: TestSuite(D).run()
225
"""
226
def __init__(self, *args, **kwds):
227
"""
228
Initialization arguments are the same as for a normal dictionary.
229
230
EXAMPLES::
231
232
sage: from sage.doctest.util import RecordingDict
233
sage: D = RecordingDict(d = 42)
234
sage: D.got
235
set([])
236
"""
237
dict.__init__(self, *args, **kwds)
238
self.start()
239
240
def start(self):
241
"""
242
We track which variables have been set or retrieved.
243
This function initializes these lists to be empty.
244
245
EXAMPLES::
246
247
sage: from sage.doctest.util import RecordingDict
248
sage: D = RecordingDict(d = 42)
249
sage: D.set
250
set([])
251
sage: D['a'] = 4
252
sage: D.set
253
set(['a'])
254
sage: D.start(); D.set
255
set([])
256
"""
257
self.set = set([])
258
self.got = set([])
259
260
def __getitem__(self, name):
261
"""
262
EXAMPLES::
263
264
sage: from sage.doctest.util import RecordingDict
265
sage: D = RecordingDict(d = 42)
266
sage: D['a'] = 4
267
sage: D.got
268
set([])
269
sage: D['a'] # indirect doctest
270
4
271
sage: D.got
272
set([])
273
sage: D['d']
274
42
275
sage: D.got
276
set(['d'])
277
"""
278
if name not in self.set:
279
self.got.add(name)
280
return dict.__getitem__(self, name)
281
282
def __setitem__(self, name, value):
283
"""
284
EXAMPLES::
285
286
sage: from sage.doctest.util import RecordingDict
287
sage: D = RecordingDict(d = 42)
288
sage: D['a'] = 4 # indirect doctest
289
sage: D.set
290
set(['a'])
291
"""
292
self.set.add(name)
293
dict.__setitem__(self, name, value)
294
295
def __delitem__(self, name):
296
"""
297
EXAMPLES::
298
299
sage: from sage.doctest.util import RecordingDict
300
sage: D = RecordingDict(d = 42)
301
sage: del D['d'] # indirect doctest
302
sage: D.set
303
set(['d'])
304
"""
305
self.set.add(name)
306
dict.__delitem__(self, name)
307
308
def get(self, name, default=None):
309
"""
310
EXAMPLES::
311
312
sage: from sage.doctest.util import RecordingDict
313
sage: D = RecordingDict(d = 42)
314
sage: D.get('d')
315
42
316
sage: D.got
317
set(['d'])
318
sage: D.get('not_here')
319
sage: sorted(list(D.got))
320
['d', 'not_here']
321
"""
322
if name not in self.set:
323
self.got.add(name)
324
return dict.get(self, name, default)
325
326
def copy(self):
327
"""
328
Note that set and got are not copied.
329
330
EXAMPLES::
331
332
sage: from sage.doctest.util import RecordingDict
333
sage: D = RecordingDict(d = 42)
334
sage: D['a'] = 4
335
sage: D.set
336
set(['a'])
337
sage: E = D.copy()
338
sage: E.set
339
set([])
340
sage: sorted(E.keys())
341
['a', 'd']
342
"""
343
return RecordingDict(dict.copy(self))
344
345
def __reduce__(self):
346
"""
347
Pickling.
348
349
EXAMPLES::
350
351
sage: from sage.doctest.util import RecordingDict
352
sage: D = RecordingDict(d = 42)
353
sage: D['a'] = 4
354
sage: D.get('not_here')
355
sage: E = loads(dumps(D))
356
sage: E.got
357
set(['not_here'])
358
"""
359
return make_recording_dict, (dict(self), self.set, self.got)
360
361
def make_recording_dict(D, st, gt):
362
"""
363
Auxilliary function for pickling.
364
365
EXAMPLES::
366
367
sage: from sage.doctest.util import make_recording_dict
368
sage: D = make_recording_dict({'a':4,'d':42},set([]),set(['not_here']))
369
sage: sorted(D.items())
370
[('a', 4), ('d', 42)]
371
sage: D.got
372
set(['not_here'])
373
"""
374
ans = RecordingDict(D)
375
ans.set = st
376
ans.got = gt
377
return ans
378
379
class NestedName:
380
"""
381
Class used to construct fully qualified names based on indentation level.
382
383
EXAMPLES::
384
385
sage: from sage.doctest.util import NestedName
386
sage: qname = NestedName('sage.categories.algebras')
387
sage: qname[0] = 'Algebras'; qname
388
sage.categories.algebras.Algebras
389
sage: qname[4] = '__contains__'; qname
390
sage.categories.algebras.Algebras.__contains__
391
sage: qname[4] = 'ParentMethods'
392
sage: qname[8] = 'from_base_ring'; qname
393
sage.categories.algebras.Algebras.ParentMethods.from_base_ring
394
395
TESTS::
396
397
sage: TestSuite(qname).run()
398
"""
399
def __init__(self, base):
400
"""
401
INPUT:
402
403
- base -- a string: the name of the module.
404
405
EXAMPLES::
406
407
sage: from sage.doctest.util import NestedName
408
sage: qname = NestedName('sage.categories.algebras')
409
sage: qname
410
sage.categories.algebras
411
"""
412
self.all = [base]
413
414
def __setitem__(self, index, value):
415
"""
416
Sets the value at a given indentation level.
417
418
INPUT:
419
420
- index -- a positive integer, the indentation level (often a multiple of 4, but not necessarily)
421
- value -- a string, the name of the class or function at that indentation level.
422
423
EXAMPLES::
424
425
sage: from sage.doctest.util import NestedName
426
sage: qname = NestedName('sage.categories.algebras')
427
sage: qname[1] = 'Algebras' # indirect doctest
428
sage: qname
429
sage.categories.algebras.Algebras
430
sage: qname.all
431
['sage.categories.algebras', None, 'Algebras']
432
"""
433
if index < 0:
434
raise ValueError
435
while len(self.all) <= index:
436
self.all.append(None)
437
self.all[index+1:] = [value]
438
439
def __str__(self):
440
"""
441
Returns a .-separated string giving the full name.
442
443
EXAMPLES::
444
445
sage: from sage.doctest.util import NestedName
446
sage: qname = NestedName('sage.categories.algebras')
447
sage: qname[1] = 'Algebras'
448
sage: qname[44] = 'at_the_end_of_the_universe'
449
sage: str(qname) # indirect doctest
450
'sage.categories.algebras.Algebras.at_the_end_of_the_universe'
451
"""
452
return self.__repr__()
453
454
def __repr__(self):
455
"""
456
Returns a .-separated string giving the full name.
457
458
EXAMPLES::
459
460
sage: from sage.doctest.util import NestedName
461
sage: qname = NestedName('sage.categories.algebras')
462
sage: qname[1] = 'Algebras'
463
sage: qname[44] = 'at_the_end_of_the_universe'
464
sage: print qname # indirect doctest
465
sage.categories.algebras.Algebras.at_the_end_of_the_universe
466
"""
467
return '.'.join(a for a in self.all if a is not None)
468
469
def __cmp__(self, other):
470
"""
471
Comparison is just comparison of the underlying lists.
472
473
EXAMPLES::
474
475
sage: from sage.doctest.util import NestedName
476
sage: qname = NestedName('sage.categories.algebras')
477
sage: qname2 = NestedName('sage.categories.algebras')
478
sage: qname == qname2
479
True
480
sage: qname[0] = 'Algebras'
481
sage: qname2[2] = 'Algebras'
482
sage: repr(qname) == repr(qname2)
483
True
484
sage: qname == qname2
485
False
486
"""
487
c = cmp(type(self), type(other))
488
if c: return c
489
return cmp(self.all, other.all)
490
491