Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/doctest/sources.py
8817 views
1
"""
2
Classes for sources of doctests
3
4
This module defines various classes for sources from which doctests
5
originate, such as files, functions or database entries.
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 <[email protected]>
14
# Robert Bradshaw <[email protected]>
15
# William Stein <[email protected]>
16
#
17
# Distributed under the terms of the GNU General Public License (GPL)
18
#
19
# http://www.gnu.org/licenses/
20
#*****************************************************************************
21
22
import os, sys, re, random
23
import doctest
24
from sage.misc.preparser import preparse, load
25
from sage.misc.lazy_attribute import lazy_attribute
26
from parsing import SageDocTestParser
27
from util import NestedName
28
from sage.structure.dynamic_class import dynamic_class
29
from sage.env import SAGE_SRC, SAGE_LOCAL
30
31
# Python file parsing
32
triple_quotes = re.compile("\s*[rRuU]*((''')|(\"\"\"))")
33
name_regex = re.compile(r".*\s(\w+)([(].*)?:")
34
35
# LaTeX file parsing
36
begin_verb = re.compile(r"\s*\\begin{verbatim}")
37
end_verb = re.compile(r"\s*\\end{verbatim}\s*(%link)?")
38
skip = re.compile(r".*%skip.*")
39
40
# ReST file parsing
41
link_all = re.compile(r"^\s*\.\.\s+linkall\s*$")
42
double_colon = re.compile(r"^(\s*).*::\s*$")
43
44
whitespace = re.compile("\s*")
45
bitness_marker = re.compile('#.*(32|64)-bit')
46
bitness_value = '64' if sys.maxint > (1 << 32) else '32'
47
48
# For neutralizing doctests
49
find_prompt = re.compile(r"^(\s*)(>>>|sage:)(.*)")
50
51
# For testing that enough doctests are created
52
sagestart = re.compile(r"^\s*(>>> |sage: )\s*[^#\s]")
53
untested = re.compile("(not implemented|not tested)")
54
55
56
def get_basename(path):
57
"""
58
This function returns the basename of the given path, e.g. sage.doctest.sources or doc.ru.tutorial.tour_advanced
59
60
EXAMPLES::
61
62
sage: from sage.doctest.sources import get_basename
63
sage: from sage.env import SAGE_SRC
64
sage: import os
65
sage: get_basename(os.path.join(SAGE_SRC,'sage','doctest','sources.py'))
66
'sage.doctest.sources'
67
"""
68
if path is None:
69
return None
70
if not os.path.exists(path):
71
return path
72
path = os.path.abspath(path)
73
root = os.path.dirname(path)
74
# If the file is in the sage library, we can use our knowledge of
75
# the directory structure
76
dev = SAGE_SRC
77
sp = os.path.join(SAGE_LOCAL, 'lib', 'python', 'site-packages')
78
if path.startswith(dev):
79
# there will be a branch name
80
i = path.find(os.path.sep, len(dev))
81
if i == -1:
82
# this source is the whole library....
83
return path
84
root = path[:i]
85
elif path.startswith(sp):
86
root = path[:len(sp)]
87
else:
88
# If this file is in some python package we can see how deep
89
# it goes by the presence of __init__.py files.
90
while os.path.exists(os.path.join(root, '__init__.py')):
91
root = os.path.dirname(root)
92
fully_qualified_path = os.path.splitext(path[len(root) + 1:])[0]
93
if os.path.split(path)[1] == '__init__.py':
94
fully_qualified_path = fully_qualified_path[:-9]
95
return fully_qualified_path.replace(os.path.sep, '.')
96
97
class DocTestSource(object):
98
"""
99
This class provides a common base class for different sources of doctests.
100
101
INPUT:
102
103
- ``options`` -- a :class:`sage.doctest.control.DocTestDefaults`
104
instance or equivalent.
105
"""
106
def __init__(self, options):
107
"""
108
Initialization.
109
110
EXAMPLES::
111
112
sage: from sage.doctest.control import DocTestDefaults
113
sage: from sage.doctest.sources import FileDocTestSource
114
sage: from sage.env import SAGE_SRC
115
sage: import os
116
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
117
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
118
sage: TestSuite(FDS).run()
119
"""
120
self.options = options
121
122
def __cmp__(self, other):
123
"""
124
Comparison is just by comparison of attributes.
125
126
EXAMPLES::
127
128
sage: from sage.doctest.control import DocTestDefaults
129
sage: from sage.doctest.sources import FileDocTestSource
130
sage: from sage.env import SAGE_SRC
131
sage: import os
132
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
133
sage: DD = DocTestDefaults()
134
sage: FDS = FileDocTestSource(filename,DD)
135
sage: FDS2 = FileDocTestSource(filename,DD)
136
sage: FDS == FDS2
137
True
138
"""
139
c = cmp(type(self), type(other))
140
if c: return c
141
return cmp(self.__dict__, other.__dict__)
142
143
def _process_doc(self, doctests, doc, namespace, start):
144
"""
145
Appends doctests defined in ``doc`` to the list ``doctests``.
146
147
This function is called when a docstring block is completed
148
(either by ending a triple quoted string in a Python file,
149
unindenting from a comment block in a ReST file, or ending a
150
verbatim environment in a LaTeX file.
151
152
INPUT:
153
154
- ``doctests`` -- a running list of doctests to which the new
155
test(s) will be appended.
156
157
- ``doc`` -- a list of lines of a docstring, each including
158
the trailing newline.
159
160
- ``namespace`` -- a dictionary or
161
:class:`sage.doctest.util.RecordingDict`, used in the
162
creation of new :class:`doctest.DocTest`s.
163
164
- ``start`` -- an integer, giving the line number of the start
165
of this docstring in the larger file.
166
167
EXAMPLES::
168
169
sage: from sage.doctest.control import DocTestDefaults
170
sage: from sage.doctest.sources import FileDocTestSource
171
sage: from sage.doctest.parsing import SageDocTestParser
172
sage: from sage.env import SAGE_SRC
173
sage: import os
174
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','util.py')
175
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
176
sage: doctests, _ = FDS.create_doctests({})
177
sage: manual_doctests = []
178
sage: for dt in doctests:
179
....: FDS.qualified_name = dt.name
180
....: FDS._process_doc(manual_doctests, dt.docstring, {}, dt.lineno-1)
181
sage: doctests == manual_doctests
182
True
183
"""
184
docstring = "".join(doc)
185
new_doctests = self.parse_docstring(docstring, namespace, start)
186
for dt in new_doctests:
187
if len(dt.examples) > 0 and not (hasattr(dt.examples[-1],'sage_source')
188
and dt.examples[-1].sage_source == "sig_on_count()\n"):
189
# Line number refers to the end of the docstring
190
sigon = doctest.Example("sig_on_count()\n", "0\n", lineno=docstring.count("\n"))
191
sigon.sage_source = "sig_on_count()\n"
192
dt.examples.append(sigon)
193
doctests.append(dt)
194
195
def _create_doctests(self, namespace, tab_okay=None):
196
"""
197
Creates a list doctests defined in this source.
198
199
This function collects functionality common to file and string
200
sources, and is called by
201
:meth:`FileDocTestSource.create_doctests`.
202
203
INPUT:
204
205
- ``namespace`` -- a dictionary or
206
:class:`sage.doctest.util.RecordingDict`, used in the
207
creation of new :class:`doctest.DocTest`s.
208
209
- ``tab_okay`` -- whether tabs are allowed in this source.
210
211
OUTPUT:
212
213
- ``doctests`` -- a list of doctests defined by this source
214
215
- ``extras`` -- a dictionary with ``extras['tab']`` either
216
False or a list of linenumbers on which tabs appear.
217
218
EXAMPLES::
219
220
sage: from sage.doctest.control import DocTestDefaults
221
sage: from sage.doctest.sources import FileDocTestSource
222
sage: from sage.doctest.util import NestedName
223
sage: from sage.env import SAGE_SRC
224
sage: import os
225
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
226
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
227
sage: FDS.qualified_name = NestedName('sage.doctest.sources')
228
sage: doctests, extras = FDS._create_doctests({})
229
sage: len(doctests)
230
40
231
sage: extras['tab']
232
False
233
"""
234
if tab_okay is None:
235
tab_okay = isinstance(self,TexSource)
236
self._init()
237
self.line_shift = 0
238
self.parser = SageDocTestParser(self.options.long, self.options.optional)
239
self.linking = False
240
doctests = []
241
in_docstring = False
242
tab_found = False
243
unparsed_doc = False
244
doc = []
245
start = None
246
tab_locations = []
247
for lineno, line in self:
248
if "\t" in line:
249
tab_locations.append(str(lineno+1))
250
if "SAGE_DOCTEST_ALLOW_TABS" in line:
251
tab_okay = True
252
just_finished = False
253
if in_docstring:
254
if self.ending_docstring(line):
255
in_docstring = False
256
just_finished = True
257
self._process_doc(doctests, doc, namespace, start)
258
unparsed_doc = False
259
else:
260
bitness = bitness_marker.search(line)
261
if bitness:
262
if bitness.groups()[0] != bitness_value:
263
self.line_shift += 1
264
continue
265
else:
266
line = line[:bitness.start()] + "\n"
267
if self.line_shift and sagestart.match(line):
268
# We insert blank lines to make up for the removed lines
269
doc.extend(["\n"]*self.line_shift)
270
self.line_shift = 0
271
doc.append(line)
272
unparsed_doc = True
273
if not in_docstring and (not just_finished or self.start_finish_can_overlap):
274
# to get line numbers in linked docstrings correct we
275
# append a blank line to the doc list.
276
doc.append("\n")
277
if not line.strip():
278
continue
279
if self.starting_docstring(line):
280
in_docstring = True
281
if self.linking:
282
# If there's already a doctest, we overwrite it.
283
if len(doctests) > 0:
284
doctests.pop()
285
if start is None:
286
start = lineno
287
doc = []
288
else:
289
self.line_shift = 0
290
start = lineno
291
doc = []
292
# In ReST files we can end the file without decreasing the indentation level.
293
if unparsed_doc:
294
self._process_doc(doctests, doc, namespace, start)
295
296
extras = dict(tab = not tab_okay and tab_locations,
297
optionals = self.parser.optionals)
298
if self.options.randorder is not None and self.options.randorder is not False:
299
# we want to randomize even when self.randorder = 0
300
random.seed(self.options.randorder)
301
randomized = []
302
while len(doctests) > 0:
303
i = random.randint(0, len(doctests)-1)
304
randomized.append(doctests.pop(i))
305
return randomized, extras
306
else:
307
return doctests, extras
308
309
class StringDocTestSource(DocTestSource):
310
r"""
311
This class creates doctests from a string.
312
313
INPUT:
314
315
- ``basename`` -- string such as 'sage.doctests.sources', going
316
into the names of created doctests and examples.
317
318
- ``source`` -- a string, giving the source code to be parsed for
319
doctests.
320
321
- ``options`` -- a :class:`sage.doctest.control.DocTestDefaults`
322
or equivalent.
323
324
- ``printpath`` -- a string, to be used in place of a filename
325
when doctest failures are displayed.
326
327
- ``lineno_shift`` -- an integer (default: 0) by which to shift
328
the line numbers of all doctests defined in this string.
329
330
EXAMPLES::
331
332
sage: from sage.doctest.control import DocTestDefaults
333
sage: from sage.doctest.sources import StringDocTestSource, PythonSource
334
sage: from sage.structure.dynamic_class import dynamic_class
335
sage: s = "'''\n sage: 2 + 2\n 4\n'''"
336
sage: PythonStringSource = dynamic_class('PythonStringSource',(StringDocTestSource, PythonSource))
337
sage: PSS = PythonStringSource('<runtime>', s, DocTestDefaults(), 'runtime')
338
sage: dt, extras = PSS.create_doctests({})
339
sage: len(dt)
340
1
341
sage: extras['tab']
342
[]
343
"""
344
def __init__(self, basename, source, options, printpath, lineno_shift=0):
345
r"""
346
Initialization
347
348
TESTS::
349
350
sage: from sage.doctest.control import DocTestDefaults
351
sage: from sage.doctest.sources import StringDocTestSource, PythonSource
352
sage: from sage.structure.dynamic_class import dynamic_class
353
sage: s = "'''\n sage: 2 + 2\n 4\n'''"
354
sage: PythonStringSource = dynamic_class('PythonStringSource',(StringDocTestSource, PythonSource))
355
sage: PSS = PythonStringSource('<runtime>', s, DocTestDefaults(), 'runtime')
356
sage: TestSuite(PSS).run()
357
"""
358
self.qualified_name = NestedName(basename)
359
self.printpath = printpath
360
self.source = source
361
self.lineno_shift = lineno_shift
362
DocTestSource.__init__(self, options)
363
364
def __iter__(self):
365
"""
366
Iterating over this source yields pairs ``(lineno, line)``.
367
368
EXAMPLES::
369
370
sage: from sage.doctest.control import DocTestDefaults
371
sage: from sage.doctest.sources import StringDocTestSource, PythonSource
372
sage: from sage.structure.dynamic_class import dynamic_class
373
sage: s = "'''\n sage: 2 + 2\n 4\n'''"
374
sage: PythonStringSource = dynamic_class('PythonStringSource',(StringDocTestSource, PythonSource))
375
sage: PSS = PythonStringSource('<runtime>', s, DocTestDefaults(), 'runtime')
376
sage: for n, line in PSS:
377
....: print n, line,
378
0 '''
379
1 sage: 2 + 2
380
2 4
381
3 '''
382
"""
383
for lineno, line in enumerate(self.source.split('\n')):
384
yield lineno + self.lineno_shift, line + '\n'
385
386
def create_doctests(self, namespace):
387
r"""
388
Creates doctests from this string.
389
390
INPUT:
391
392
- ``namespace`` -- a dictionary or :class:`sage.doctest.util.RecordingDict`.
393
394
OUTPUT:
395
396
- ``doctests`` -- a list of doctests defined by this string
397
398
- ``tab_locations`` -- either False or a list of linenumbers
399
on which tabs appear.
400
401
EXAMPLES::
402
403
sage: from sage.doctest.control import DocTestDefaults
404
sage: from sage.doctest.sources import StringDocTestSource, PythonSource
405
sage: from sage.structure.dynamic_class import dynamic_class
406
sage: s = "'''\n sage: 2 + 2\n 4\n'''"
407
sage: PythonStringSource = dynamic_class('PythonStringSource',(StringDocTestSource, PythonSource))
408
sage: PSS = PythonStringSource('<runtime>', s, DocTestDefaults(), 'runtime')
409
sage: dt, tabs = PSS.create_doctests({})
410
sage: for t in dt:
411
....: print t.name, t.examples[0].sage_source
412
<runtime> 2 + 2
413
"""
414
return self._create_doctests(namespace)
415
416
class FileDocTestSource(DocTestSource):
417
"""
418
This class creates doctests from a file.
419
420
INPUT:
421
422
- ``path`` -- string, the filename
423
424
- ``options`` -- a :class:`sage.doctest.control.DocTestDefaults`
425
instance or equivalent.
426
427
EXAMPLES::
428
429
sage: from sage.doctest.control import DocTestDefaults
430
sage: from sage.doctest.sources import FileDocTestSource
431
sage: from sage.env import SAGE_SRC
432
sage: import os
433
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
434
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
435
sage: FDS.basename
436
'sage.doctest.sources'
437
438
TESTS::
439
440
sage: TestSuite(FDS).run()
441
"""
442
def __init__(self, path, options):
443
"""
444
Initialization.
445
446
EXAMPLES::
447
448
sage: from sage.doctest.control import DocTestDefaults
449
sage: from sage.doctest.sources import FileDocTestSource
450
sage: from sage.env import SAGE_SRC
451
sage: import os
452
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
453
sage: FDS = FileDocTestSource(filename,DocTestDefaults(randorder=0))
454
sage: FDS.options.randorder
455
0
456
"""
457
self.path = path
458
DocTestSource.__init__(self, options)
459
base, ext = os.path.splitext(path)
460
if ext in ('.py', '.pyx', '.pxi', '.sage', '.spyx'):
461
self.__class__ = dynamic_class('PythonFileSource',(FileDocTestSource,PythonSource))
462
elif ext == '.tex':
463
self.__class__ = dynamic_class('TexFileSource',(FileDocTestSource,TexSource))
464
elif ext == '.rst':
465
self.__class__ = dynamic_class('RestFileSource',(FileDocTestSource,RestSource))
466
467
def __iter__(self):
468
r"""
469
Iterating over this source yields pairs ``(lineno, line)``.
470
471
EXAMPLES::
472
473
sage: from sage.doctest.control import DocTestDefaults
474
sage: from sage.doctest.sources import FileDocTestSource
475
sage: filename = tmp_filename(ext=".py")
476
sage: s = "'''\n sage: 2 + 2\n 4\n'''"
477
sage: open(filename, 'w').write(s)
478
sage: FDS = FileDocTestSource(filename, DocTestDefaults())
479
sage: for n, line in FDS:
480
....: print n, line,
481
0 '''
482
1 sage: 2 + 2
483
2 4
484
3 '''
485
"""
486
with open(self.path) as source:
487
for lineno, line in enumerate(source):
488
yield lineno, line
489
490
@lazy_attribute
491
def printpath(self):
492
"""
493
Whether the path is printed absolutely or relatively depends on an option.
494
495
EXAMPLES::
496
497
sage: from sage.doctest.control import DocTestDefaults
498
sage: from sage.doctest.sources import FileDocTestSource
499
sage: from sage.env import SAGE_SRC
500
sage: import os
501
sage: root = os.path.realpath(os.path.join(SAGE_SRC,'sage'))
502
sage: filename = os.path.join(root,'doctest','sources.py')
503
sage: cwd = os.getcwd()
504
sage: os.chdir(root)
505
sage: FDS = FileDocTestSource(filename,DocTestDefaults(randorder=0,abspath=False))
506
sage: FDS.printpath
507
'doctest/sources.py'
508
sage: FDS = FileDocTestSource(filename,DocTestDefaults(randorder=0,abspath=True))
509
sage: FDS.printpath
510
'.../sage/doctest/sources.py'
511
sage: os.chdir(cwd)
512
"""
513
if self.options.abspath:
514
return os.path.abspath(self.path)
515
else:
516
relpath = os.path.relpath(self.path)
517
if relpath.startswith(".." + os.path.sep):
518
return self.path
519
else:
520
return relpath
521
522
@lazy_attribute
523
def basename(self):
524
"""
525
The basename of this file source, e.g. sage.doctest.sources
526
527
EXAMPLES::
528
529
sage: from sage.doctest.control import DocTestDefaults
530
sage: from sage.doctest.sources import FileDocTestSource
531
sage: from sage.env import SAGE_SRC
532
sage: import os
533
sage: filename = os.path.join(SAGE_SRC,'sage','rings','integer.pyx')
534
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
535
sage: FDS.basename
536
'sage.rings.integer'
537
"""
538
return get_basename(self.path)
539
540
@lazy_attribute
541
def in_lib(self):
542
"""
543
Whether this file should be considered part of the Sage library.
544
545
Such files aren't loaded before running tests.
546
547
EXAMPLES::
548
549
sage: from sage.doctest.control import DocTestDefaults
550
sage: from sage.doctest.sources import FileDocTestSource
551
sage: from sage.env import SAGE_SRC
552
sage: import os
553
sage: filename = os.path.join(SAGE_SRC,'sage','rings','integer.pyx')
554
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
555
sage: FDS.in_lib
556
True
557
558
You can override the default::
559
560
sage: FDS = FileDocTestSource("hello_world.py",DocTestDefaults())
561
sage: FDS.in_lib
562
False
563
sage: FDS = FileDocTestSource("hello_world.py",DocTestDefaults(force_lib=True))
564
sage: FDS.in_lib
565
True
566
"""
567
return (self.options.force_lib or
568
self.basename.startswith('sage.') or
569
self.basename.startswith('doc.') or
570
self.basename.startswith('sagenb.'))
571
572
def create_doctests(self, namespace):
573
r"""
574
Returns a list of doctests for this file.
575
576
INPUT:
577
578
- ``namespace`` -- a dictionary or :class:`sage.doctest.util.RecordingDict`.
579
580
OUTPUT:
581
582
- ``doctests`` -- a list of doctests defined in this file.
583
584
- ``extras`` -- a dictionary
585
586
EXAMPLES::
587
588
sage: from sage.doctest.control import DocTestDefaults
589
sage: from sage.doctest.sources import FileDocTestSource
590
sage: from sage.env import SAGE_SRC
591
sage: import os
592
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
593
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
594
sage: doctests, extras = FDS.create_doctests(globals())
595
sage: len(doctests)
596
40
597
sage: extras['tab']
598
False
599
600
We give a self referential example::
601
602
sage: doctests[17].name
603
'sage.doctest.sources.FileDocTestSource.create_doctests'
604
sage: doctests[17].examples[10].source
605
'doctests[Integer(17)].examples[Integer(10)].source\n'
606
607
TESTS:
608
609
We check that we correctly process results that depend on 32
610
vs 64 bit architecture::
611
612
sage: import sys
613
sage: bitness = '64' if sys.maxint > (1 << 32) else '32'
614
sage: n = -920390823904823094890238490238484; hash(n) > 0
615
False # 32-bit
616
True # 64-bit
617
sage: ex = doctests[17].examples[13]
618
sage: (bitness == '64' and ex.want == 'True \n') or (bitness == '32' and ex.want == 'False \n')
619
True
620
621
We check that lines starting with a # aren't doctested::
622
623
#sage: raise RuntimeError
624
"""
625
if not os.path.exists(self.path):
626
import errno
627
raise IOError(errno.ENOENT, "File does not exist", self.path)
628
base, filename = os.path.split(self.path)
629
_, ext = os.path.splitext(filename)
630
if not self.in_lib and ext in ('.py', '.pyx', '.sage', '.spyx'):
631
cwd = os.getcwd()
632
if base:
633
os.chdir(base)
634
try:
635
load(filename, namespace) # errors raised here will be caught in DocTestTask
636
finally:
637
os.chdir(cwd)
638
self.qualified_name = NestedName(self.basename)
639
return self._create_doctests(namespace)
640
641
def _test_enough_doctests(self, check_extras=True, verbose=True):
642
"""
643
This function checks to see that the doctests are not getting
644
unexpectedly skipped. It uses a different (and simpler) code
645
path than the doctest creation functions, so there are a few
646
files in Sage that it counts incorrectly.
647
648
INPUT:
649
650
- ``check_extras`` -- bool (default True), whether to check if
651
doctests are created that don't correspond to either a
652
``sage: `` or a ``>>> `` prompt.
653
654
- ``verbose`` -- bool (default True), whether to print
655
offending line numbers when there are missing or extra
656
tests.
657
658
TESTS::
659
660
sage: from sage.doctest.control import DocTestDefaults
661
sage: from sage.doctest.sources import FileDocTestSource
662
sage: from sage.env import SAGE_SRC
663
sage: cwd = os.getcwd()
664
sage: os.chdir(SAGE_SRC)
665
sage: import itertools
666
sage: for path, dirs, files in itertools.chain(os.walk('sage'), os.walk('doc')): # long time
667
....: path = os.path.relpath(path)
668
....: dirs.sort(); files.sort()
669
....: for F in files:
670
....: _, ext = os.path.splitext(F)
671
....: if ext in ('.py', '.pyx', '.pxi', '.sage', '.spyx', '.rst'):
672
....: filename = os.path.join(path, F)
673
....: FDS = FileDocTestSource(filename, DocTestDefaults(long=True,optional=True))
674
....: FDS._test_enough_doctests(verbose=False)
675
There are 7 tests in sage/combinat/dyck_word.py that are not being run
676
There are 18 tests in sage/combinat/partition.py that are not being run
677
There are 15 tests in sage/combinat/permutation.py that are not being run
678
There are 14 tests in sage/combinat/skew_partition.py that are not being run
679
There are 18 tests in sage/combinat/tableau.py that are not being run
680
There are 8 tests in sage/combinat/crystals/tensor_product.py that are not being run
681
There are 15 tests in sage/combinat/root_system/cartan_type.py that are not being run
682
There are 8 tests in sage/combinat/root_system/type_A.py that are not being run
683
There are 8 tests in sage/combinat/root_system/type_G.py that are not being run
684
There are 3 unexpected tests being run in sage/doctest/parsing.py
685
There are 1 unexpected tests being run in sage/doctest/reporting.py
686
There are 9 tests in sage/graphs/graph_plot.py that are not being run
687
There are 3 tests in sage/rings/invariant_theory.py that are not being run
688
sage: os.chdir(cwd)
689
"""
690
expected = []
691
rest = isinstance(self, RestSource)
692
if rest:
693
skipping = False
694
in_block = False
695
last_line = ''
696
for lineno, line in self:
697
if not line.strip():
698
continue
699
if rest:
700
if line.strip().startswith(".. nodoctest"):
701
return
702
# We need to track blocks in order to figure out whether we're skipping.
703
if in_block:
704
indent = whitespace.match(line).end()
705
if indent <= starting_indent:
706
in_block = False
707
skipping = False
708
if not in_block:
709
m = double_colon.match(line)
710
if m and not line.strip().startswith(".."):
711
if ".. skip" in last_line:
712
skipping = True
713
in_block = True
714
starting_indent = whitespace.match(line).end()
715
last_line = line
716
if (not rest or in_block) and sagestart.match(line) and not ((rest and skipping) or untested.search(line.lower())):
717
expected.append(lineno+1)
718
actual = []
719
tests, _ = self.create_doctests({})
720
for dt in tests:
721
if len(dt.examples) > 0:
722
for ex in dt.examples[:-1]: # the last entry is a sig_on_count()
723
actual.append(dt.lineno + ex.lineno + 1)
724
shortfall = sorted(list(set(expected).difference(set(actual))))
725
extras = sorted(list(set(actual).difference(set(expected))))
726
if len(actual) == len(expected):
727
if len(shortfall) == 0: return
728
dif = extras[0] - shortfall[0]
729
for e, s in zip(extras[1:],shortfall[1:]):
730
if dif != e - s:
731
break
732
else:
733
print "There are %s tests in %s that are shifted by %s"%(len(shortfall),self.path,dif)
734
if verbose:
735
print " The correct line numbers are %s"%(", ".join([str(n) for n in shortfall]))
736
return
737
elif len(actual) < len(expected):
738
print "There are %s tests in %s that are not being run"%(len(expected) - len(actual), self.path)
739
elif check_extras:
740
print "There are %s unexpected tests being run in %s"%(len(actual) - len(expected), self.path)
741
if verbose:
742
if shortfall:
743
print " Tests on lines %s are not run"%(", ".join([str(n) for n in shortfall]))
744
if check_extras and extras:
745
print " Tests on lines %s seem extraneous"%(", ".join([str(n) for n in extras]))
746
747
class SourceLanguage:
748
"""
749
An abstract class for functions that depend on the programming language of a doctest source.
750
751
Currently supported languages include Python, ReST and LaTeX.
752
"""
753
def parse_docstring(self, docstring, namespace, start):
754
"""
755
Return a list of doctest defined in this docstring.
756
757
This function is called by :meth:`DocTestSource._process_doc`.
758
The default implementation, defined here, is to use the
759
:class:`sage.doctest.parsing.SageDocTestParser` attached to
760
this source to get doctests from the docstring.
761
762
INPUT:
763
764
- ``docstring`` -- a string containing documentation and tests.
765
766
- ``namespace`` -- a dictionary or :class:`sage.doctest.util.RecordingDict`.
767
768
- ``start`` -- an integer, one less than the starting line number
769
770
EXAMPLES::
771
772
sage: from sage.doctest.control import DocTestDefaults
773
sage: from sage.doctest.sources import FileDocTestSource
774
sage: from sage.doctest.parsing import SageDocTestParser
775
sage: from sage.doctest.util import NestedName
776
sage: from sage.env import SAGE_SRC
777
sage: import os
778
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','util.py')
779
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
780
sage: doctests, _ = FDS.create_doctests({})
781
sage: for dt in doctests:
782
....: FDS.qualified_name = dt.name
783
....: dt.examples = dt.examples[:-1] # strip off the sig_on() test
784
....: assert(FDS.parse_docstring(dt.docstring,{},dt.lineno-1)[0] == dt)
785
"""
786
return [self.parser.get_doctest(docstring, namespace, str(self.qualified_name),
787
self.printpath, start + 1)]
788
789
class PythonSource(SourceLanguage):
790
"""
791
This class defines the functions needed for the extraction of doctests from python sources.
792
793
EXAMPLES::
794
795
sage: from sage.doctest.control import DocTestDefaults
796
sage: from sage.doctest.sources import FileDocTestSource
797
sage: from sage.env import SAGE_SRC
798
sage: import os
799
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
800
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
801
sage: type(FDS)
802
<class 'sage.doctest.sources.PythonFileSource'>
803
"""
804
# The same line can't both start and end a docstring
805
start_finish_can_overlap = False
806
807
def _init(self):
808
"""
809
This function is called before creating doctests from a Python source.
810
811
EXAMPLES::
812
813
sage: from sage.doctest.control import DocTestDefaults
814
sage: from sage.doctest.sources import FileDocTestSource
815
sage: from sage.env import SAGE_SRC
816
sage: import os
817
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
818
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
819
sage: FDS._init()
820
sage: FDS.last_indent
821
-1
822
"""
823
self.last_indent = -1
824
self.last_line = None
825
self.quotetype = None
826
self.paren_count = 0
827
self.bracket_count = 0
828
self.curly_count = 0
829
self.code_wrapping = False
830
831
def _update_quotetype(self, line):
832
r"""
833
Updates the track of what kind of quoted string we're in.
834
835
We need to track whether we're inside a triple quoted
836
string, since a triple quoted string that starts a line
837
could be the end of a string and thus not the beginning of a
838
doctest (see sage.misc.sageinspect for an example).
839
840
To do this tracking we need to track whether we're inside a
841
string at all, since ''' inside a string doesn't start a
842
triple quote (see the top of this file for an example).
843
844
We also need to track parentheses and brackets, since we only
845
want to update our record of last line and indentation level
846
when the line is actually over.
847
848
EXAMPLES::
849
850
sage: from sage.doctest.control import DocTestDefaults
851
sage: from sage.doctest.sources import FileDocTestSource
852
sage: from sage.env import SAGE_SRC
853
sage: import os
854
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
855
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
856
sage: FDS._init()
857
sage: FDS._update_quotetype('\"\"\"'); print " ".join(list(FDS.quotetype))
858
" " "
859
sage: FDS._update_quotetype("'''"); print " ".join(list(FDS.quotetype))
860
" " "
861
sage: FDS._update_quotetype('\"\"\"'); print FDS.quotetype
862
None
863
sage: FDS._update_quotetype("triple_quotes = re.compile(\"\\s*[rRuU]*((''')|(\\\"\\\"\\\"))\")")
864
sage: print FDS.quotetype
865
None
866
sage: FDS._update_quotetype("''' Single line triple quoted string \\''''")
867
sage: print FDS.quotetype
868
None
869
sage: FDS._update_quotetype("' Lots of \\\\\\\\'")
870
sage: print FDS.quotetype
871
None
872
"""
873
def _update_parens(start,end=None):
874
self.paren_count += line.count("(",start,end) - line.count(")",start,end)
875
self.bracket_count += line.count("[",start,end) - line.count("]",start,end)
876
self.curly_count += line.count("{",start,end) - line.count("}",start,end)
877
pos = 0
878
while pos < len(line):
879
if self.quotetype is None:
880
next_single = line.find("'",pos)
881
next_double = line.find('"',pos)
882
if next_single == -1 and next_double == -1:
883
next_comment = line.find("#",pos)
884
if next_comment == -1:
885
_update_parens(pos)
886
else:
887
_update_parens(pos,next_comment)
888
break
889
elif next_single == -1:
890
m = next_double
891
elif next_double == -1:
892
m = next_single
893
else:
894
m = min(next_single, next_double)
895
next_comment = line.find('#',pos,m)
896
if next_comment != -1:
897
_update_parens(pos,next_comment)
898
break
899
_update_parens(pos,m)
900
if m+2 < len(line) and line[m] == line[m+1] == line[m+2]:
901
self.quotetype = line[m:m+3]
902
pos = m+3
903
else:
904
self.quotetype = line[m]
905
pos = m+1
906
else:
907
next = line.find(self.quotetype,pos)
908
if next == -1:
909
break
910
elif next == 0 or line[next-1] != '\\':
911
pos = next + len(self.quotetype)
912
self.quotetype = None
913
else:
914
# We need to worry about the possibility that
915
# there are an even number of backslashes before
916
# the quote, in which case it is not escaped
917
count = 1
918
slashpos = next - 2
919
while slashpos >= pos and line[slashpos] == '\\':
920
count += 1
921
slashpos -= 1
922
if count % 2 == 0:
923
pos = next + len(self.quotetype)
924
self.quotetype = None
925
else:
926
# The possible ending quote was escaped.
927
pos = next + 1
928
929
def starting_docstring(self, line):
930
"""
931
Determines whether the input line starts a docstring.
932
933
If the input line does start a docstring (a triple quote),
934
then this function updates ``self.qualified_name``.
935
936
INPUT:
937
938
- ``line`` -- a string, one line of an input file
939
940
OUTPUT:
941
942
- either None or a Match object.
943
944
EXAMPLES::
945
946
sage: from sage.doctest.control import DocTestDefaults
947
sage: from sage.doctest.sources import FileDocTestSource
948
sage: from sage.doctest.util import NestedName
949
sage: from sage.env import SAGE_SRC
950
sage: import os
951
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
952
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
953
sage: FDS._init()
954
sage: FDS.starting_docstring("r'''")
955
<_sre.SRE_Match object at ...>
956
sage: FDS.ending_docstring("'''")
957
<_sre.SRE_Match object at ...>
958
sage: FDS.qualified_name = NestedName(FDS.basename)
959
sage: FDS.starting_docstring("class MyClass(object):")
960
sage: FDS.starting_docstring(" def hello_world(self):")
961
sage: FDS.starting_docstring(" '''")
962
<_sre.SRE_Match object at ...>
963
sage: FDS.qualified_name
964
sage.doctest.sources.MyClass.hello_world
965
sage: FDS.ending_docstring(" '''")
966
<_sre.SRE_Match object at ...>
967
sage: FDS.starting_docstring("class NewClass(object):")
968
sage: FDS.starting_docstring(" '''")
969
<_sre.SRE_Match object at ...>
970
sage: FDS.qualified_name
971
sage.doctest.sources.NewClass
972
"""
973
indent = whitespace.match(line).end()
974
quotematch = None
975
if self.quotetype is None:
976
# We're not inside a triple quote
977
if line[indent] != '#' and (indent == 0 or indent > self.last_indent):
978
quotematch = triple_quotes.match(line)
979
# It would be nice to only run the name_regex when
980
# quotematch wasn't None, but then we mishandle classes
981
# that don't have a docstring.
982
if not self.code_wrapping and self.last_indent >= 0 and indent > self.last_indent:
983
name = name_regex.match(self.last_line)
984
if name:
985
name = name.groups()[0]
986
self.qualified_name[indent] = name
987
elif quotematch:
988
self.qualified_name[indent] = '?'
989
self._update_quotetype(line)
990
if line[indent] != '#' and not self.code_wrapping:
991
self.last_line, self.last_indent = line, indent
992
self.code_wrapping = not (self.paren_count == self.bracket_count == self.curly_count == 0)
993
return quotematch
994
995
def ending_docstring(self, line):
996
r"""
997
Determines whether the input line ends a docstring.
998
999
INPUT:
1000
1001
- ``line`` -- a string, one line of an input file.
1002
1003
OUTPUT:
1004
1005
- an object that, when evaluated in a boolean context, gives
1006
True or False depending on whether the input line marks the
1007
end of a docstring.
1008
1009
EXAMPLES::
1010
1011
sage: from sage.doctest.control import DocTestDefaults
1012
sage: from sage.doctest.sources import FileDocTestSource
1013
sage: from sage.doctest.util import NestedName
1014
sage: from sage.env import SAGE_SRC
1015
sage: import os
1016
sage: filename = os.path.join(SAGE_SRC,'sage','doctest','sources.py')
1017
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1018
sage: FDS._init()
1019
sage: FDS.quotetype = "'''"
1020
sage: FDS.ending_docstring("'''")
1021
<_sre.SRE_Match object at ...>
1022
sage: FDS.ending_docstring('\"\"\"')
1023
"""
1024
quotematch = triple_quotes.match(line)
1025
if quotematch is not None and quotematch.groups()[0] != self.quotetype:
1026
quotematch = None
1027
self._update_quotetype(line)
1028
return quotematch
1029
1030
def _neutralize_doctests(self, reindent):
1031
r"""
1032
Returns a string containing the source of self, but with
1033
doctests modified so they aren't tested.
1034
1035
This function is used in creating doctests for ReST files,
1036
since docstrings of Python functions defined inside verbatim
1037
blocks screw up Python's doctest parsing.
1038
1039
INPUT:
1040
1041
- ``reindent`` -- an integer, the number of spaces to indent
1042
the result.
1043
1044
EXAMPLES::
1045
1046
sage: from sage.doctest.control import DocTestDefaults
1047
sage: from sage.doctest.sources import StringDocTestSource, PythonSource
1048
sage: from sage.structure.dynamic_class import dynamic_class
1049
sage: s = "'''\n sage: 2 + 2\n 4\n'''"
1050
sage: PythonStringSource = dynamic_class('PythonStringSource',(StringDocTestSource, PythonSource))
1051
sage: PSS = PythonStringSource('<runtime>', s, DocTestDefaults(), 'runtime')
1052
sage: print PSS._neutralize_doctests(0),
1053
'''
1054
safe: 2 + 2
1055
4
1056
'''
1057
"""
1058
neutralized = []
1059
in_docstring = False
1060
self._init()
1061
for lineno, line in self:
1062
if not line.strip():
1063
neutralized.append(line)
1064
elif in_docstring:
1065
if self.ending_docstring(line):
1066
in_docstring = False
1067
neutralized.append(" "*reindent + find_prompt.sub(r"\1safe:\3",line))
1068
else:
1069
if self.starting_docstring(line):
1070
in_docstring = True
1071
neutralized.append(" "*reindent + line)
1072
return "".join(neutralized)
1073
1074
class TexSource(SourceLanguage):
1075
"""
1076
This class defines the functions needed for the extraction of
1077
doctests from a LaTeX source.
1078
1079
EXAMPLES::
1080
1081
sage: from sage.doctest.control import DocTestDefaults
1082
sage: from sage.doctest.sources import FileDocTestSource
1083
sage: filename = "sage_paper.tex"
1084
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1085
sage: type(FDS)
1086
<class 'sage.doctest.sources.TexFileSource'>
1087
"""
1088
# The same line can't both start and end a docstring
1089
start_finish_can_overlap = False
1090
1091
def _init(self):
1092
"""
1093
This function is called before creating doctests from a Tex file.
1094
1095
EXAMPLES::
1096
1097
sage: from sage.doctest.control import DocTestDefaults
1098
sage: from sage.doctest.sources import FileDocTestSource
1099
sage: filename = "sage_paper.tex"
1100
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1101
sage: FDS._init()
1102
sage: FDS.skipping
1103
False
1104
"""
1105
self.skipping = False
1106
1107
def starting_docstring(self, line):
1108
r"""
1109
Determines whether the input line starts a docstring.
1110
1111
Docstring blocks in tex files are defined by verbatim
1112
environments, and can be linked together by adding %link
1113
immediately after the \end{verbatim}.
1114
1115
Within a verbatim block, you can tell Sage not to
1116
process the rest of the block by including a %skip line.
1117
1118
INPUT:
1119
1120
- ``line`` -- a string, one line of an input file
1121
1122
OUTPUT:
1123
1124
- a boolean giving whether the input line marks the
1125
start of a docstring (verbatim block).
1126
1127
EXAMPLES::
1128
1129
sage: from sage.doctest.control import DocTestDefaults
1130
sage: from sage.doctest.sources import FileDocTestSource
1131
sage: filename = "sage_paper.tex"
1132
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1133
sage: FDS._init()
1134
1135
We start docstrings with \begin{verbatim}::
1136
1137
sage: FDS.starting_docstring(r"\begin{verbatim}")
1138
True
1139
sage: FDS.skipping
1140
False
1141
sage: FDS.ending_docstring("sage: 2+2")
1142
False
1143
sage: FDS.ending_docstring("4")
1144
False
1145
1146
To start ignoring the rest of the verbatim block, use %skip::
1147
1148
sage: FDS.ending_docstring("%skip")
1149
True
1150
sage: FDS.skipping
1151
True
1152
sage: FDS.starting_docstring("sage: raise RuntimeError")
1153
False
1154
1155
You can even pretend to start another verbatim block while skipping::
1156
1157
sage: FDS.starting_docstring(r"\begin{verbatim}")
1158
False
1159
sage: FDS.skipping
1160
True
1161
1162
To stop skipping end the verbatim block::
1163
1164
sage: FDS.starting_docstring(r"\end{verbatim} %link")
1165
False
1166
sage: FDS.skipping
1167
False
1168
1169
Linking works even when the block was ended while skipping::
1170
1171
sage: FDS.linking
1172
True
1173
sage: FDS.starting_docstring(r"\begin{verbatim}")
1174
True
1175
"""
1176
if self.skipping:
1177
if self.ending_docstring(line, check_skip=False):
1178
self.skipping = False
1179
return False
1180
return bool(begin_verb.match(line))
1181
1182
def ending_docstring(self, line, check_skip=True):
1183
r"""
1184
Determines whether the input line ends a docstring.
1185
1186
Docstring blocks in tex files are defined by verbatim
1187
environments, and can be linked together by adding %link
1188
immediately after the \end{verbatim}.
1189
1190
Within a verbatim block, you can tell Sage not to
1191
process the rest of the block by including a %skip line.
1192
1193
INPUT:
1194
1195
- ``line`` -- a string, one line of an input file
1196
1197
- ``check_skip`` -- boolean (default True), used internally in starting_docstring.
1198
1199
OUTPUT:
1200
1201
- a boolean giving whether the input line marks the
1202
end of a docstring (verbatim block).
1203
1204
EXAMPLES::
1205
1206
sage: from sage.doctest.control import DocTestDefaults
1207
sage: from sage.doctest.sources import FileDocTestSource
1208
sage: filename = "sage_paper.tex"
1209
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1210
sage: FDS._init()
1211
sage: FDS.ending_docstring(r"\end{verbatim}")
1212
True
1213
sage: FDS.linking
1214
False
1215
1216
Use %link to link with the next verbatim block::
1217
1218
sage: FDS.ending_docstring(r"\end{verbatim}%link")
1219
True
1220
sage: FDS.linking
1221
True
1222
1223
%skip also ends a docstring block::
1224
1225
sage: FDS.ending_docstring("%skip")
1226
True
1227
"""
1228
m = end_verb.match(line)
1229
if m:
1230
if m.groups()[0]:
1231
self.linking = True
1232
else:
1233
self.linking = False
1234
return True
1235
if check_skip and skip.match(line):
1236
self.skipping = True
1237
return True
1238
return False
1239
1240
class RestSource(SourceLanguage):
1241
"""
1242
This class defines the functions needed for the extraction of
1243
doctests from ReST sources.
1244
1245
EXAMPLES::
1246
1247
sage: from sage.doctest.control import DocTestDefaults
1248
sage: from sage.doctest.sources import FileDocTestSource
1249
sage: filename = "sage_doc.rst"
1250
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1251
sage: type(FDS)
1252
<class 'sage.doctest.sources.RestFileSource'>
1253
"""
1254
# The same line can both start and end a docstring
1255
start_finish_can_overlap = True
1256
1257
def _init(self):
1258
"""
1259
This function is called before creating doctests from a ReST file.
1260
1261
EXAMPLES::
1262
1263
sage: from sage.doctest.control import DocTestDefaults
1264
sage: from sage.doctest.sources import FileDocTestSource
1265
sage: filename = "sage_doc.rst"
1266
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1267
sage: FDS._init()
1268
sage: FDS.link_all
1269
False
1270
"""
1271
self.link_all = False
1272
self.last_line = ""
1273
self.last_indent = -1
1274
self.first_line = False
1275
self.skipping = False
1276
1277
def starting_docstring(self, line):
1278
"""
1279
A line ending with a double quote starts a verbatim block in a ReST file.
1280
1281
This function also determines whether the docstring block
1282
should be joined with the previous one, or should be skipped.
1283
1284
INPUT:
1285
1286
- ``line`` -- a string, one line of an input file
1287
1288
OUTPUT:
1289
1290
- either None or a Match object.
1291
1292
EXAMPLES::
1293
1294
sage: from sage.doctest.control import DocTestDefaults
1295
sage: from sage.doctest.sources import FileDocTestSource
1296
sage: filename = "sage_doc.rst"
1297
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1298
sage: FDS._init()
1299
sage: FDS.starting_docstring("Hello world::")
1300
True
1301
sage: FDS.ending_docstring(" sage: 2 + 2")
1302
False
1303
sage: FDS.ending_docstring(" 4")
1304
False
1305
sage: FDS.ending_docstring("We are now done")
1306
True
1307
sage: FDS.starting_docstring(".. link")
1308
sage: FDS.starting_docstring("::")
1309
True
1310
sage: FDS.linking
1311
True
1312
"""
1313
if link_all.match(line):
1314
self.link_all = True
1315
if self.skipping:
1316
end_block = self.ending_docstring(line)
1317
if end_block:
1318
self.skipping = False
1319
else:
1320
return False
1321
m = double_colon.match(line)
1322
starting = m and not line.strip().startswith(".. ")
1323
if starting:
1324
self.linking = self.link_all or '.. link' in self.last_line
1325
self.first_line = True
1326
indent = len(m.groups()[0])
1327
if '.. skip' in self.last_line:
1328
self.skipping = True
1329
starting = False
1330
else:
1331
indent = self.last_indent
1332
self.last_line, self.last_indent = line, indent
1333
return starting
1334
1335
def ending_docstring(self, line):
1336
"""
1337
When the indentation level drops below the initial level the
1338
block ends.
1339
1340
INPUT:
1341
1342
- ``line`` -- a string, one line of an input file
1343
1344
OUTPUT:
1345
1346
- a boolean, whether the verbatim block is ending.
1347
1348
EXAMPLES::
1349
1350
sage: from sage.doctest.control import DocTestDefaults
1351
sage: from sage.doctest.sources import FileDocTestSource
1352
sage: filename = "sage_doc.rst"
1353
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1354
sage: FDS._init()
1355
sage: FDS.starting_docstring("Hello world::")
1356
True
1357
sage: FDS.ending_docstring(" sage: 2 + 2")
1358
False
1359
sage: FDS.ending_docstring(" 4")
1360
False
1361
sage: FDS.ending_docstring("We are now done")
1362
True
1363
"""
1364
if not line.strip():
1365
return False
1366
indent = whitespace.match(line).end()
1367
if self.first_line:
1368
self.first_line = False
1369
if indent <= self.last_indent:
1370
# We didn't indent at all
1371
return True
1372
self.last_indent = indent
1373
return indent < self.last_indent
1374
1375
def parse_docstring(self, docstring, namespace, start):
1376
r"""
1377
Return a list of doctest defined in this docstring.
1378
1379
Code blocks in a REST file can contain python functions with
1380
their own docstrings in addition to in-line doctests. We want
1381
to include the tests from these inner docstrings, but Python's
1382
doctesting module has a problem if we just pass on the whole
1383
block, since it expects to get just a docstring, not the
1384
Python code as well.
1385
1386
Our solution is to create a new doctest source from this code
1387
block and append the doctests created from that source. We
1388
then replace the occurrences of "sage:" and ">>>" occurring
1389
inside a triple quote with "safe:" so that the doctest module
1390
doesn't treat them as tests.
1391
1392
EXAMPLES::
1393
1394
sage: from sage.doctest.control import DocTestDefaults
1395
sage: from sage.doctest.sources import FileDocTestSource
1396
sage: from sage.doctest.parsing import SageDocTestParser
1397
sage: from sage.doctest.util import NestedName
1398
sage: filename = "sage_doc.rst"
1399
sage: FDS = FileDocTestSource(filename,DocTestDefaults())
1400
sage: FDS.parser = SageDocTestParser(False, set(['sage']))
1401
sage: FDS.qualified_name = NestedName('sage_doc')
1402
sage: s = "Some text::\n\n def example_python_function(a, \
1403
....: b):\n '''\n Brief description \
1404
....: of function.\n\n EXAMPLES::\n\n \
1405
....: sage: test1()\n sage: test2()\n \
1406
....: '''\n return a + b\n\n sage: test3()\n\nMore \
1407
....: ReST documentation."
1408
sage: tests = FDS.parse_docstring(s, {}, 100)
1409
sage: len(tests)
1410
2
1411
sage: for ex in tests[0].examples:
1412
....: print ex.sage_source,
1413
test3()
1414
sage: for ex in tests[1].examples:
1415
....: print ex.sage_source,
1416
test1()
1417
test2()
1418
sig_on_count()
1419
"""
1420
PythonStringSource = dynamic_class("sage.doctest.sources.PythonStringSource",
1421
(StringDocTestSource, PythonSource))
1422
min_indent = self.parser._min_indent(docstring)
1423
pysource = '\n'.join([l[min_indent:] for l in docstring.split('\n')])
1424
inner_source = PythonStringSource(self.basename, pysource,
1425
self.options,
1426
self.printpath, lineno_shift=start+1)
1427
inner_doctests, _ = inner_source._create_doctests(namespace, True)
1428
safe_docstring = inner_source._neutralize_doctests(min_indent)
1429
outer_doctest = self.parser.get_doctest(safe_docstring, namespace,
1430
str(self.qualified_name),
1431
self.printpath, start + 1)
1432
return [outer_doctest] + inner_doctests
1433
1434
class DictAsObject(dict):
1435
"""
1436
A simple subclass of dict that inserts the items from the initializing dictionary into attributes.
1437
1438
EXAMPLES::
1439
1440
sage: from sage.doctest.sources import DictAsObject
1441
sage: D = DictAsObject({'a':2})
1442
sage: D.a
1443
2
1444
"""
1445
def __init__(self, attrs):
1446
"""
1447
Initialization.
1448
1449
INPUT:
1450
1451
- ``attrs`` -- a dictionary.
1452
1453
EXAMPLES::
1454
1455
sage: from sage.doctest.sources import DictAsObject
1456
sage: D = DictAsObject({'a':2})
1457
sage: D.a == D['a']
1458
True
1459
sage: D.a
1460
2
1461
"""
1462
super(DictAsObject, self).__init__(attrs)
1463
self.__dict__.update(attrs)
1464
1465
def __setitem__(self, ky, val):
1466
"""
1467
We preserve the ability to access entries through either the
1468
dictionary or attribute interfaces.
1469
1470
EXAMPLES::
1471
1472
sage: from sage.doctest.sources import DictAsObject
1473
sage: D = DictAsObject({})
1474
sage: D['a'] = 2
1475
sage: D.a
1476
2
1477
"""
1478
super(DictAsObject, self).__setitem__(ky, val)
1479
try:
1480
super(DictAsObject, self).__setattr__(ky, val)
1481
except TypeError:
1482
pass
1483
1484
def __setattr__(self, ky, val):
1485
"""
1486
We preserve the ability to access entries through either the
1487
dictionary or attribute interfaces.
1488
1489
EXAMPLES::
1490
1491
sage: from sage.doctest.sources import DictAsObject
1492
sage: D = DictAsObject({})
1493
sage: D.a = 2
1494
sage: D['a']
1495
2
1496
"""
1497
super(DictAsObject, self).__setitem__(ky, val)
1498
super(DictAsObject, self).__setattr__(ky, val)
1499
1500