-
-
Notifications
You must be signed in to change notification settings - Fork 561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add style guide / reference for # optional - sage....
doctest tags, extend sage -t
and sage -fixdoctests
for modularization tasks
#35749
Changes from all commits
664c56c
d7ecd4d
e7173cd
3aacb73
bfb9a52
4b69756
d46fb19
5dc088f
1ad2776
eef016f
74b98cf
2440c0b
647380c
2bd55ab
9485097
6dd4afd
f7152bd
87f5e15
bdc4232
0596705
131e1f9
d9d1900
dda8c28
e9f38c0
9541219
6e25da2
a14580e
48b1660
58d857e
8ab0383
52fb3cc
28019f4
65212a3
2a2279f
66f1a7a
f6d9acd
f407653
f7d7e5b
c890919
7870c3d
6f230ff
40d44fe
7400851
c54d3d1
231886d
793ec77
747b3d4
f78ce64
2d72755
87ce0db
bb873c2
499d68f
7d291cd
6410b89
dc2f81e
eb089fd
88451cd
b405d87
b567951
7e7bd57
80d15a3
843b479
5a47c79
7708ced
c9e338a
6ac8b55
a19bdd3
f2fd934
1d544b0
feca1dc
9413da0
038bb55
b86ffb3
57c5c7d
d75181e
7765125
84004a6
bbd8270
4ffec03
80e088d
f0d851a
7b79b47
ebfd164
e0c1d84
93c11f1
1130c26
514d1f7
65e6985
5934fe7
51d406d
6f2ffd0
914dd03
ce84e70
c999202
243654a
981ba19
3d38f98
9db9bf7
6298290
ff2b675
627c5e8
2ef982c
ffd6177
8e41453
ef0b5cf
16771d6
87b4e1d
8938897
edaeab2
1ecb25c
d63808a
6204e0c
0ca9016
d09ac6f
e7a0cc0
b0bbedc
557098e
b50ca94
af3128c
91bc915
f9add88
95f5383
fb689a2
7a002a4
db3569b
9109d0e
ba8dd56
c5d2adf
31a30aa
3106a06
48ea62c
8623513
31097fc
4f55787
c6d1b89
636a05d
2625d2a
d5672a1
9132250
eba5b80
4ad6345
627c9c0
44e5752
a3e61ad
6019181
37d2303
26d6766
bf270c7
19eee80
3c44670
30e7dae
b801474
fafaaf2
8d25508
0c42086
6b5b82c
44549f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -935,6 +935,15 @@ written. | |
Sage does not know about the function ``AA()`` by default, so it needs to be | ||
imported before it is tested. Hence the first line in the example. | ||
|
||
All blocks within the same docstring are linked: Variables set | ||
in a doctest keep their values for the remaining doctests within the | ||
same docstring. It is good practice to use different variable names for different | ||
values, as it makes the data flow in the examples easier to understand | ||
for human readers. (It also makes the data flow analysis in the | ||
Sage doctester more precise.) In particular, when unrelated examples | ||
appear in the same docstring, do not use the same variable name | ||
for both examples. | ||
|
||
- **Preparsing:** As in Sage's console, `4/3` returns `4/3` and not | ||
`1.3333333333333333` as in Python 3.8. Testing occurs with full Sage | ||
preparsing of input within the standard Sage shell environment, as | ||
|
@@ -958,6 +967,78 @@ written. | |
5 | ||
7 | ||
|
||
- **Wrap long doctest lines:** Note that all doctests in EXAMPLES blocks | ||
get formatted as part of our HTML and PDF reference manuals. Our HTML manuals | ||
are formatted using the responsive design provided by the | ||
:ref:`Furo theme <spkg_furo>`. Even when the browser window is expanded to | ||
make use of the full width of a wide desktop screen, the style will not | ||
allow code boxes to grow arbitrarily wide. | ||
|
||
It is best to wrap long lines when possible so that readers do not have to | ||
scroll horizontally (back and forth) to follow an example. | ||
|
||
- Try to wrap long lines somewhere around columns 80 to 88 | ||
and try to never exceed column 95 in the source file. | ||
(Columns numbers are from the left margin in the source file; | ||
these rules work no matter how deep the docstring may be nested | ||
because also the formatted output will be nested.) | ||
|
||
- If you have to break an expression at a place that is not already | ||
nested in parentheses, wrap it in parentheses:: | ||
|
||
sage: (len(list(Permutations(['a', 'b', 'c', 'd', 'e', 'f', 'g']))) | ||
....: == len(list(Permutations(7)))) | ||
True | ||
|
||
- If the output in your only example is very wide and cannot be reasonably | ||
reformatted to fit (for example, large symbolic matrices or numbers with many digits), | ||
consider showing a smaller example first. | ||
|
||
- No need to wrap long ``import`` statements. Typically, the ``import`` statements | ||
are not the interesting parts of the doctests. Users only need to be able to | ||
copy-paste them into a Sage session or source file:: | ||
|
||
sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict, MPolynomialRing_polydict_domain # this is fine | ||
|
||
- Wrap and indent long output to maximize readability in the source code | ||
and in the HTML output. But do not wrap strings:: | ||
|
||
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi | ||
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ) | ||
sage: S = P.subscheme([]) | ||
sage: T = P.subscheme([x - y]) | ||
sage: U = AlgebraicScheme_quasi(S, T); U | ||
Quasi-projective subscheme X - Y of Projective Space of dimension 2 | ||
over Integer Ring, | ||
where X is defined by: (no polynomials) | ||
and Y is defined by: x - y | ||
sage: U._repr_() # this is fine | ||
'Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:\n (no polynomials)\nand Y is defined by:\n x - y' | ||
|
||
Also, if there is no whitespace in the doctest output where you could wrap the line, | ||
do not add such whitespace. Just don't wrap the line:: | ||
|
||
sage: B47 = RibbonGraph(4,7, bipartite=True); B47 | ||
Ribbon graph of genus 9 and 1 boundary components | ||
sage: B47.sigma() # this is fine | ||
(1,2,3,4,5,6,7)(8,9,10,11,12,13,14)(15,16,17,18,19,20,21)(22,23,24,25,26,27,28)(29,30,31,32)(33,34,35,36)(37,38,39,40)(41,42,43,44)(45,46,47,48)(49,50,51,52)(53,54,55,56) | ||
|
||
- Doctest tags for modularization purposes such as ``# needs sage.modules`` | ||
(see :ref:`section-further_conventions`) should be aligned at column 88. | ||
Clean lines from consistent alignment help reduce visual clutter. | ||
Moreover, at the maximum window width, only the word ``# needs`` will be | ||
visible in the HTML output without horizontal scrolling, striking a | ||
thoughtfully chosen balance between presenting | ||
the information and reducing visual clutter. (How much can be seen may be | ||
browser-dependent, of course.) In visually dense doctests, you can try to sculpt out visual space to separate | ||
the test commands from the annotation. | ||
|
||
- Doctest tags such as ``# optional - pynormaliz`` that make the doctest | ||
conditional on the presence of optional packages, on the other hand, | ||
should be aligned so that they are visible without having to scroll horizontally. | ||
The :ref:`doctest fixer <section-fixdoctests-optional-needs>` uses | ||
tab stops at columns 48, 56, 64, ... for these tags. | ||
|
||
- **Python3 print:** Python3 syntax for print must be used in Sage | ||
code and doctests. If you use an old-style print in doctests, it | ||
will raise a SyntaxError:: | ||
|
@@ -1131,44 +1212,25 @@ framework. Here is a comprehensive list: | |
Neither of this applies to files or directories which are explicitly given | ||
as command line arguments: those are always tested. | ||
|
||
- **optional:** A line flagged with ``optional - keyword`` is not tested unless | ||
the ``--optional=keyword`` flag is passed to ``sage -t`` (see | ||
- **optional/needs:** A line tagged with ``optional - FEATURE`` | ||
or ``needs FEATURE`` is not tested unless the ``--optional=KEYWORD`` flag | ||
is passed to ``sage -t`` (see | ||
:ref:`section-optional-doctest-flag`). The main applications are: | ||
|
||
- **optional packages:** When a line requires an optional package to be | ||
installed (e.g. the ``sloane_database`` package):: | ||
|
||
sage: SloaneEncyclopedia[60843] # optional - sloane_database | ||
|
||
.. NOTE:: | ||
|
||
If one of the first 10 lines of a file starts with any of | ||
``r""" sage.doctest: optional - keyword`` | ||
(or ``""" sage.doctest: optional - keyword`` | ||
or ``# sage.doctest: optional - keyword`` | ||
or ``% sage.doctest: optional - keyword`` | ||
or ``.. sage.doctest: optional - keyword``, | ||
or any of these with different spacing), | ||
then that file will be skipped unless | ||
the ``--optional=keyword`` flag is passed to ``sage -t``. | ||
|
||
This does not apply to files which are explicitly given | ||
as command line arguments: those are always tested. | ||
|
||
If you add such a line to a file, you are strongly encouraged | ||
to add a note to the module-level documentation, saying that | ||
the doctests in this file will be skipped unless the | ||
appropriate conditions are met. | ||
|
||
- **internet:** For lines that require an internet connection:: | ||
|
||
sage: oeis(60843) # optional - internet | ||
A060843: Busy Beaver problem: a(n) = maximal number of steps that an | ||
n-state Turing machine can make on an initially blank tape before | ||
eventually halting. | ||
|
||
- **bug:** For lines that describe bugs. Alternatively, use ``# known bug`` | ||
instead: it is an alias for ``optional bug``. | ||
- **known bugs:** For lines that describe known bugs, you can use ``# optional - bug``, | ||
although ``# known bug`` is preferred. | ||
|
||
.. CODE-BLOCK:: rest | ||
|
||
|
@@ -1179,21 +1241,55 @@ framework. Here is a comprehensive list: | |
sage: 2+2 # known bug | ||
5 | ||
|
||
- **modularization:** To enable | ||
:ref:`separate testing of the distribution packages <section-doctesting-venv>` | ||
of the modularized Sage library, doctests that depend on features provided | ||
by other distribution packages can be tagged ``# needs FEATURE``. | ||
For example: | ||
|
||
.. CODE-BLOCK:: rest | ||
|
||
Consider the following calculation:: | ||
|
||
sage: a = AA(2).sqrt() # needs sage.rings.number_field | ||
sage: b = sqrt(3) # needs sage.symbolic | ||
sage: a + AA(b) # needs sage.rings.number_field sage.symbolic | ||
3.146264369941973? | ||
|
||
.. NOTE:: | ||
|
||
- Any words after ``# optional`` are interpreted as a list of | ||
- Any words after ``# optional`` and ``# needs`` are interpreted as a list of | ||
package (spkg) names or other feature tags, separated by spaces. | ||
|
||
- Any punctuation other than underscores (``_``) and periods (``.``), | ||
that is, commas, hyphens, semicolons, ..., after the | ||
first word ends the list of packages. Hyphens or colons between the | ||
word ``optional`` and the first package name are allowed. Therefore, | ||
you should not write ``optional: needs package CHomP`` but simply | ||
``optional: CHomP``. | ||
you should not write ``# optional - depends on package CHomP`` but simply | ||
``# optional - CHomP``. | ||
|
||
- Optional tags are case-insensitive, so you could also write ``optional: | ||
- Optional tags are case-insensitive, so you could also write ``# optional - | ||
chOMP``. | ||
|
||
If ``# optional`` or ``# needs`` is placed right after the ``sage:`` prompt, | ||
it is a block-scoped tag, which applies to all doctest lines until | ||
a blank line is encountered. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As for "codeblock-scoped tag", the initial word "code" seems redundant since the tags are already used within code block. The term "block-scoped tag" is already long, so why make it longer? I prefer "block-scoped tag". On the other hand, the term "persistent tag" that I originally used is shorter but somewhat obscure... I will not insist if you disagree though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "block-scoped" is fine with me, I'll change it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in c6d1b89 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. |
||
These tags can also be applied to an entire file. If one of the first 10 lines | ||
of a file starts with any of ``r""" sage.doctest: optional - FEATURE``, | ||
``# sage.doctest: needs FEATURE``, or ``.. sage.doctest: optional - FEATURE`` | ||
(in ``.rst`` files), etc., then this applies to all doctests in this file. | ||
|
||
When a file is skipped that was explicitly given as a command line argument, | ||
a warning is displayed. | ||
|
||
.. NOTE:: | ||
|
||
If you add such a line to a file, you are strongly encouraged | ||
to add a note to the module-level documentation, saying that | ||
the doctests in this file will be skipped unless the | ||
appropriate conditions are met. | ||
|
||
- **indirect doctest:** in the docstring of a function ``A(...)``, a line | ||
calling ``A`` and in which the name ``A`` does not appear should have this | ||
flag. This prevents ``sage --coverage <file>`` from reporting the docstring as | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understood the meaning of
--only-lib
by the statement "Use the option --only-lib to skip the source files of all Python/Cython modules that are not installed in the virtual environment..." in the documentation. I still don't understand the meaning of the existing--force-lib
. The common-lib
refers to the same thing, "the library installed to a virtual environment"?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, in both cases,
lib
refers to the Sage library.When
sage -t
is applied to a Python file outside of the Sage library (= the installed copy or "the" source tree; technically, a file that does not look like it belongs to a source tree with the top-level package "sage"), then it first callsload
on that file, which adds stuff to the global namespace. This is a feature that simplifies testing user code, as one does not have to sayfrom .... import
in every doctest.--force-lib
turns this mechanism off and treats that file like any file that is part of the Sage library.The
lib
in--only-lib
is a bit different. It also checks whether the given file looks like it belongs to a source tree with the top-level package "sage", but then it checks whether that is installed as a module in the installed Sage library.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Then how about
--only-installed
instead of--only-lib
to avoid possible confusion with thelib
in--force-lib
? Perhaps together with--all-installed
instead of--installed
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like
--only-installed
as a replacement for--only-lib
because--installed
runs doctests as they appear in the installed files, whereas--only-lib
runs the doctests in the given files and only filters by an additional conditionThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then
--if-installed
as it filters out not-installed files? This is my last try :-)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, that's a good solution. Done in fafaaf2