Skip to content

Commit f2abd5a

Browse files
author
Release Manager
committed
gh-35749: Add style guide / reference for `# optional - sage....` doctest tags, extend `sage -t` and `sage -fixdoctests` for modularization tasks <!-- Please provide a concise, informative and self-explanatory title. --> <!-- Don't put issue numbers in the title. Put it in the Description below. --> <!-- For example, instead of "Fixes #12345", use "Add a new method to multiply two integers" --> ### 📚 Description <!-- Describe your changes here in detail. --> - Fixing the handling of file-level `# optional` tags. - Some files were not being doctested; fixing the recently introduced errors in doctests. - Implementing block-scoped tags (originally done in PR #35779, merged here) - Expanding the documentation on the `# optional` / `# needs` tags used for modularization purposes, with examples. - Adding features `sage.modular`, `sage.numerical.mip`, `sage.rings.complex_double`, `sage.sat` - The tools `sage -t` and `sage --fixdoctests` receive some new options for modularization tasks (see added documentation): ``` $ make pypi-wheels $ make SAGE_CHECK=yes sagemath-modules $ ./sage --fixdoctests --distribution sagemath-modules \ src/sage/combinat/root_system/root_lattice_realization_algebras.py ``` (example uses #35095) - Suppressing `# optional`/`# needs` of present features in the help system . <!-- Why is this change required? What problem does it solve? --> Motivated by the sage-devel thread https://groups.google.com/g/sage- devel/c/utA0N1it0Eo (2023-06) <!-- If this PR resolves an open issue, please link to it here. For example "Fixes #12345". --> - Resolves #35790 - Resolves #35750 - Part of #29705 <!-- If your change requires a documentation PR, please link it appropriately. --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. It should be `[x]` not `[x ]`. --> - [x] The title is concise, informative, and self-explanatory. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [x] I have updated the documentation accordingly. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on - #12345: short description why this is a dependency - #34567: ... --> - Depends on #35820 (merged here) - Vote at https://groups.google.com/g/sage-devel/c/8KZNRBs6F6U (result: https://groups.google.com/g/sage-devel/c/MtS2u3VbJEo) <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> URL: #35749 Reported by: Matthias Köppe Reviewer(s): Kwankyu Lee, Matthias Köppe
2 parents 3a51d8c + 44549f6 commit f2abd5a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+5074
-2853
lines changed

src/bin/sage-fixdoctests

Lines changed: 333 additions & 74 deletions
Large diffs are not rendered by default.

src/bin/sage-runtests

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ if __name__ == "__main__":
5656
help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; '
5757
'if "all" is listed, will also hide features corresponding to all optional or experimental packages; '
5858
'if "optional" is listed, will also hide features corresponding to optional packages.')
59+
parser.add_argument("--probe", metavar="FEATURES", default="",
60+
help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; '
61+
'report the tests that pass nevertheless')
5962
parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests")
6063
parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests",
6164
default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED"))
@@ -66,6 +69,7 @@ if __name__ == "__main__":
6669
parser.add_argument("-i", "--initial", action="store_true", default=False, help="only show the first failure in each file")
6770
parser.add_argument("--exitfirst", action="store_true", default=False, help="end the test run immediately after the first failure or unexpected exception")
6871
parser.add_argument("--force_lib", "--force-lib", action="store_true", default=False, help="do not import anything from the tested file(s)")
72+
parser.add_argument("--if-installed", action="store_true", default=False, help="skip Python/Cython files that are not installed as modules")
6973
parser.add_argument("--abspath", action="store_true", default=False, help="print absolute paths rather than relative paths")
7074
parser.add_argument("--verbose", action="store_true", default=False, help="print debugging output during the test")
7175
parser.add_argument("-d", "--debug", action="store_true", default=False, help="drop into a python debugger when an unexpected error is raised")

src/doc/de/tutorial/latex.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,17 +319,18 @@ lässt. Diese Liste wird verwaltet durch die Befehle
319319
``latex.add_to_mathjax_avoid_list`` und
320320
``latex.mathjax_avoid_list``. ::
321321

322-
sage: latex.mathjax_avoid_list([]) # not tested
323-
sage: latex.mathjax_avoid_list() # not tested
322+
sage: # not tested
323+
sage: latex.mathjax_avoid_list([])
324+
sage: latex.mathjax_avoid_list()
324325
[]
325-
sage: latex.mathjax_avoid_list(['foo', 'bar']) # not tested
326-
sage: latex.mathjax_avoid_list() # not tested
326+
sage: latex.mathjax_avoid_list(['foo', 'bar'])
327+
sage: latex.mathjax_avoid_list()
327328
['foo', 'bar']
328-
sage: latex.add_to_mathjax_avoid_list('tikzpicture') # not tested
329-
sage: latex.mathjax_avoid_list() # not tested
329+
sage: latex.add_to_mathjax_avoid_list('tikzpicture')
330+
sage: latex.mathjax_avoid_list()
330331
['foo', 'bar', 'tikzpicture']
331-
sage: latex.mathjax_avoid_list([]) # not tested
332-
sage: latex.mathjax_avoid_list() # not tested
332+
sage: latex.mathjax_avoid_list([])
333+
sage: latex.mathjax_avoid_list()
333334
[]
334335

335336
Nehmen wir an ein LaTeX-Ausdruck wurde im Notebook durch ``view()``

src/doc/en/developer/coding_basics.rst

Lines changed: 124 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,15 @@ written.
935935
Sage does not know about the function ``AA()`` by default, so it needs to be
936936
imported before it is tested. Hence the first line in the example.
937937

938+
All blocks within the same docstring are linked: Variables set
939+
in a doctest keep their values for the remaining doctests within the
940+
same docstring. It is good practice to use different variable names for different
941+
values, as it makes the data flow in the examples easier to understand
942+
for human readers. (It also makes the data flow analysis in the
943+
Sage doctester more precise.) In particular, when unrelated examples
944+
appear in the same docstring, do not use the same variable name
945+
for both examples.
946+
938947
- **Preparsing:** As in Sage's console, `4/3` returns `4/3` and not
939948
`1.3333333333333333` as in Python 3.8. Testing occurs with full Sage
940949
preparsing of input within the standard Sage shell environment, as
@@ -958,6 +967,78 @@ written.
958967
5
959968
7
960969

970+
- **Wrap long doctest lines:** Note that all doctests in EXAMPLES blocks
971+
get formatted as part of our HTML and PDF reference manuals. Our HTML manuals
972+
are formatted using the responsive design provided by the
973+
:ref:`Furo theme <spkg_furo>`. Even when the browser window is expanded to
974+
make use of the full width of a wide desktop screen, the style will not
975+
allow code boxes to grow arbitrarily wide.
976+
977+
It is best to wrap long lines when possible so that readers do not have to
978+
scroll horizontally (back and forth) to follow an example.
979+
980+
- Try to wrap long lines somewhere around columns 80 to 88
981+
and try to never exceed column 95 in the source file.
982+
(Columns numbers are from the left margin in the source file;
983+
these rules work no matter how deep the docstring may be nested
984+
because also the formatted output will be nested.)
985+
986+
- If you have to break an expression at a place that is not already
987+
nested in parentheses, wrap it in parentheses::
988+
989+
sage: (len(list(Permutations(['a', 'b', 'c', 'd', 'e', 'f', 'g'])))
990+
....: == len(list(Permutations(7))))
991+
True
992+
993+
- If the output in your only example is very wide and cannot be reasonably
994+
reformatted to fit (for example, large symbolic matrices or numbers with many digits),
995+
consider showing a smaller example first.
996+
997+
- No need to wrap long ``import`` statements. Typically, the ``import`` statements
998+
are not the interesting parts of the doctests. Users only need to be able to
999+
copy-paste them into a Sage session or source file::
1000+
1001+
sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict, MPolynomialRing_polydict_domain # this is fine
1002+
1003+
- Wrap and indent long output to maximize readability in the source code
1004+
and in the HTML output. But do not wrap strings::
1005+
1006+
sage: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_quasi
1007+
sage: P.<x, y, z> = ProjectiveSpace(2, ZZ)
1008+
sage: S = P.subscheme([])
1009+
sage: T = P.subscheme([x - y])
1010+
sage: U = AlgebraicScheme_quasi(S, T); U
1011+
Quasi-projective subscheme X - Y of Projective Space of dimension 2
1012+
over Integer Ring,
1013+
where X is defined by: (no polynomials)
1014+
and Y is defined by: x - y
1015+
sage: U._repr_() # this is fine
1016+
'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'
1017+
1018+
Also, if there is no whitespace in the doctest output where you could wrap the line,
1019+
do not add such whitespace. Just don't wrap the line::
1020+
1021+
sage: B47 = RibbonGraph(4,7, bipartite=True); B47
1022+
Ribbon graph of genus 9 and 1 boundary components
1023+
sage: B47.sigma() # this is fine
1024+
(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)
1025+
1026+
- Doctest tags for modularization purposes such as ``# needs sage.modules``
1027+
(see :ref:`section-further_conventions`) should be aligned at column 88.
1028+
Clean lines from consistent alignment help reduce visual clutter.
1029+
Moreover, at the maximum window width, only the word ``# needs`` will be
1030+
visible in the HTML output without horizontal scrolling, striking a
1031+
thoughtfully chosen balance between presenting
1032+
the information and reducing visual clutter. (How much can be seen may be
1033+
browser-dependent, of course.) In visually dense doctests, you can try to sculpt out visual space to separate
1034+
the test commands from the annotation.
1035+
1036+
- Doctest tags such as ``# optional - pynormaliz`` that make the doctest
1037+
conditional on the presence of optional packages, on the other hand,
1038+
should be aligned so that they are visible without having to scroll horizontally.
1039+
The :ref:`doctest fixer <section-fixdoctests-optional-needs>` uses
1040+
tab stops at columns 48, 56, 64, ... for these tags.
1041+
9611042
- **Python3 print:** Python3 syntax for print must be used in Sage
9621043
code and doctests. If you use an old-style print in doctests, it
9631044
will raise a SyntaxError::
@@ -1131,44 +1212,25 @@ framework. Here is a comprehensive list:
11311212
Neither of this applies to files or directories which are explicitly given
11321213
as command line arguments: those are always tested.
11331214

1134-
- **optional:** A line flagged with ``optional - keyword`` is not tested unless
1135-
the ``--optional=keyword`` flag is passed to ``sage -t`` (see
1215+
- **optional/needs:** A line tagged with ``optional - FEATURE``
1216+
or ``needs FEATURE`` is not tested unless the ``--optional=KEYWORD`` flag
1217+
is passed to ``sage -t`` (see
11361218
:ref:`section-optional-doctest-flag`). The main applications are:
11371219

11381220
- **optional packages:** When a line requires an optional package to be
11391221
installed (e.g. the ``sloane_database`` package)::
11401222

11411223
sage: SloaneEncyclopedia[60843] # optional - sloane_database
11421224

1143-
.. NOTE::
1144-
1145-
If one of the first 10 lines of a file starts with any of
1146-
``r""" sage.doctest: optional - keyword``
1147-
(or ``""" sage.doctest: optional - keyword``
1148-
or ``# sage.doctest: optional - keyword``
1149-
or ``% sage.doctest: optional - keyword``
1150-
or ``.. sage.doctest: optional - keyword``,
1151-
or any of these with different spacing),
1152-
then that file will be skipped unless
1153-
the ``--optional=keyword`` flag is passed to ``sage -t``.
1154-
1155-
This does not apply to files which are explicitly given
1156-
as command line arguments: those are always tested.
1157-
1158-
If you add such a line to a file, you are strongly encouraged
1159-
to add a note to the module-level documentation, saying that
1160-
the doctests in this file will be skipped unless the
1161-
appropriate conditions are met.
1162-
11631225
- **internet:** For lines that require an internet connection::
11641226

11651227
sage: oeis(60843) # optional - internet
11661228
A060843: Busy Beaver problem: a(n) = maximal number of steps that an
11671229
n-state Turing machine can make on an initially blank tape before
11681230
eventually halting.
11691231

1170-
- **bug:** For lines that describe bugs. Alternatively, use ``# known bug``
1171-
instead: it is an alias for ``optional bug``.
1232+
- **known bugs:** For lines that describe known bugs, you can use ``# optional - bug``,
1233+
although ``# known bug`` is preferred.
11721234

11731235
.. CODE-BLOCK:: rest
11741236
@@ -1179,21 +1241,55 @@ framework. Here is a comprehensive list:
11791241
sage: 2+2 # known bug
11801242
5
11811243
1244+
- **modularization:** To enable
1245+
:ref:`separate testing of the distribution packages <section-doctesting-venv>`
1246+
of the modularized Sage library, doctests that depend on features provided
1247+
by other distribution packages can be tagged ``# needs FEATURE``.
1248+
For example:
1249+
1250+
.. CODE-BLOCK:: rest
1251+
1252+
Consider the following calculation::
1253+
1254+
sage: a = AA(2).sqrt() # needs sage.rings.number_field
1255+
sage: b = sqrt(3) # needs sage.symbolic
1256+
sage: a + AA(b) # needs sage.rings.number_field sage.symbolic
1257+
3.146264369941973?
1258+
11821259
.. NOTE::
11831260

1184-
- Any words after ``# optional`` are interpreted as a list of
1261+
- Any words after ``# optional`` and ``# needs`` are interpreted as a list of
11851262
package (spkg) names or other feature tags, separated by spaces.
11861263

11871264
- Any punctuation other than underscores (``_``) and periods (``.``),
11881265
that is, commas, hyphens, semicolons, ..., after the
11891266
first word ends the list of packages. Hyphens or colons between the
11901267
word ``optional`` and the first package name are allowed. Therefore,
1191-
you should not write ``optional: needs package CHomP`` but simply
1192-
``optional: CHomP``.
1268+
you should not write ``# optional - depends on package CHomP`` but simply
1269+
``# optional - CHomP``.
11931270

1194-
- Optional tags are case-insensitive, so you could also write ``optional:
1271+
- Optional tags are case-insensitive, so you could also write ``# optional -
11951272
chOMP``.
11961273

1274+
If ``# optional`` or ``# needs`` is placed right after the ``sage:`` prompt,
1275+
it is a block-scoped tag, which applies to all doctest lines until
1276+
a blank line is encountered.
1277+
1278+
These tags can also be applied to an entire file. If one of the first 10 lines
1279+
of a file starts with any of ``r""" sage.doctest: optional - FEATURE``,
1280+
``# sage.doctest: needs FEATURE``, or ``.. sage.doctest: optional - FEATURE``
1281+
(in ``.rst`` files), etc., then this applies to all doctests in this file.
1282+
1283+
When a file is skipped that was explicitly given as a command line argument,
1284+
a warning is displayed.
1285+
1286+
.. NOTE::
1287+
1288+
If you add such a line to a file, you are strongly encouraged
1289+
to add a note to the module-level documentation, saying that
1290+
the doctests in this file will be skipped unless the
1291+
appropriate conditions are met.
1292+
11971293
- **indirect doctest:** in the docstring of a function ``A(...)``, a line
11981294
calling ``A`` and in which the name ``A`` does not appear should have this
11991295
flag. This prevents ``sage --coverage <file>`` from reporting the docstring as

0 commit comments

Comments
 (0)