diff --git a/src/doc/ca/intro/conf.py b/src/doc/ca/intro/conf.py index 2f4eb7f1873..e46ebfb8c8d 100644 --- a/src/doc/ca/intro/conf.py +++ b/src/doc/ca/intro/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/ca/intro', '{filename}'), +}) + # General information about the project. project = "Introducció de Sage" diff --git a/src/doc/common/static/custom-furo.css b/src/doc/common/static/custom-furo.css index fc76a3f7c0f..ae75c2b6383 100644 --- a/src/doc/common/static/custom-furo.css +++ b/src/doc/common/static/custom-furo.css @@ -21,3 +21,17 @@ a.pdf:hover { text-decoration: none; } +/* Style for announcement banner */ + +.announcement { + background: orange; +} + +.announcement-content { + color: black; +} + +.announcement-content a { + color: white; + text-decoration: none; +} diff --git a/src/doc/de/a_tour_of_sage/conf.py b/src/doc/de/a_tour_of_sage/conf.py index 47355ae5a22..33f9e9642b7 100644 --- a/src/doc/de/a_tour_of_sage/conf.py +++ b/src/doc/de/a_tour_of_sage/conf.py @@ -22,6 +22,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/de/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = "Ein Rundgang durch Sage" name = "a_tour_of_sage" diff --git a/src/doc/de/thematische_anleitungen/conf.py b/src/doc/de/thematische_anleitungen/conf.py index 7f2753ab0e4..d3a843c30bd 100644 --- a/src/doc/de/thematische_anleitungen/conf.py +++ b/src/doc/de/thematische_anleitungen/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/de/thematische_anleitungen', '{filename}'), +}) + # General information about the project. project = "Thematische Anleitungen" name = 'ThematischeAnleitungen-de' diff --git a/src/doc/de/tutorial/conf.py b/src/doc/de/tutorial/conf.py index 8d18c44aa6b..fe4c5b0d3e1 100644 --- a/src/doc/de/tutorial/conf.py +++ b/src/doc/de/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/de/tutorial', '{filename}'), +}) + # General information about the project. project = "Sage Tutorial" name = 'SageTutorial-de' diff --git a/src/doc/en/a_tour_of_sage/conf.py b/src/doc/en/a_tour_of_sage/conf.py index 14ecb994215..38184747c9f 100644 --- a/src/doc/en/a_tour_of_sage/conf.py +++ b/src/doc/en/a_tour_of_sage/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, f'blob/develop/src/doc/en/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = "A Tour of Sage" diff --git a/src/doc/en/constructions/conf.py b/src/doc/en/constructions/conf.py index 37215f418c6..13743e5b276 100644 --- a/src/doc/en/constructions/conf.py +++ b/src/doc/en/constructions/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/constructions', '{filename}'), +}) + # General information about the project. project = "Constructions" diff --git a/src/doc/en/developer/conf.py b/src/doc/en/developer/conf.py index 9dcfc261ed1..58e0ca995b7 100644 --- a/src/doc/en/developer/conf.py +++ b/src/doc/en/developer/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/developer', '{filename}'), +}) + # General information about the project. project = "Developer Guide" diff --git a/src/doc/en/faq/conf.py b/src/doc/en/faq/conf.py index 42c3378b129..fab823b6592 100644 --- a/src/doc/en/faq/conf.py +++ b/src/doc/en/faq/conf.py @@ -22,6 +22,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/faq', '{filename}'), +}) + # General information about the project. project = "FAQ" diff --git a/src/doc/en/installation/conf.py b/src/doc/en/installation/conf.py index e50bf3c1c57..41f91e228d0 100644 --- a/src/doc/en/installation/conf.py +++ b/src/doc/en/installation/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/installation', '{filename}'), +}) + # General information about the project. project = "Installation Guide" diff --git a/src/doc/en/prep/conf.py b/src/doc/en/prep/conf.py index bbc6663b3df..3dc26674397 100644 --- a/src/doc/en/prep/conf.py +++ b/src/doc/en/prep/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/prep', '{filename}'), +}) + # General information about the project. project = "PREP Tutorials" copyright = "2012, Rob Beezer, Karl-Dieter Crisman, and Jason Grout" diff --git a/src/doc/en/reference/conf.py b/src/doc/en/reference/conf.py index 86aa0b05a81..d9bb5da5acb 100644 --- a/src/doc/en/reference/conf.py +++ b/src/doc/en/reference/conf.py @@ -25,6 +25,11 @@ ref_src = os.path.join(SAGE_DOC_SRC, 'en', 'reference') ref_out = os.path.join(SAGE_DOC, 'html', 'en', 'reference') +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/reference/index.rst'), +}) + # General information about the project. project = "Reference Manual" diff --git a/src/doc/en/reference/conf_sub.py b/src/doc/en/reference/conf_sub.py index b6f20311d68..8346b13c9f4 100644 --- a/src/doc/en/reference/conf_sub.py +++ b/src/doc/en/reference/conf_sub.py @@ -42,6 +42,11 @@ title = name.capitalize() title = title.replace('`', '$') +# We use the directory's name to add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, f'blob/develop/src/doc/en/reference/{name}', '{filename}'), +}) + # General information about the project. project = title diff --git a/src/doc/en/thematic_tutorials/conf.py b/src/doc/en/thematic_tutorials/conf.py index 3b638d40173..19f9a3da5af 100644 --- a/src/doc/en/thematic_tutorials/conf.py +++ b/src/doc/en/thematic_tutorials/conf.py @@ -22,6 +22,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/thematic_tutorials', '{filename}'), +}) + # General information about the project. project = "Thematic Tutorials" diff --git a/src/doc/en/tutorial/conf.py b/src/doc/en/tutorial/conf.py index 8a4f626f440..7b475a3bb6e 100644 --- a/src/doc/en/tutorial/conf.py +++ b/src/doc/en/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/en/tutorial', '{filename}'), +}) + # General information about the project. project = "Tutorial" diff --git a/src/doc/es/a_tour_of_sage/conf.py b/src/doc/es/a_tour_of_sage/conf.py index 1bf598c11f5..b6f43afd2da 100644 --- a/src/doc/es/a_tour_of_sage/conf.py +++ b/src/doc/es/a_tour_of_sage/conf.py @@ -22,6 +22,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/es/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = 'Un Tour Por Sage' name = 'a_tour_of_sage' diff --git a/src/doc/es/tutorial/conf.py b/src/doc/es/tutorial/conf.py index bbebf61f532..913dfc06025 100644 --- a/src/doc/es/tutorial/conf.py +++ b/src/doc/es/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/es/tutorial', '{filename}'), +}) + # General information about the project. project = "Sage Tutorial" name = 'tutorial-es' diff --git a/src/doc/fr/a_tour_of_sage/conf.py b/src/doc/fr/a_tour_of_sage/conf.py index f6438ea695a..19c047882bf 100644 --- a/src/doc/fr/a_tour_of_sage/conf.py +++ b/src/doc/fr/a_tour_of_sage/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/fr/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = 'Sage en quelques mots' name = 'a_tour_of_sage' diff --git a/src/doc/fr/tutorial/conf.py b/src/doc/fr/tutorial/conf.py index f44315072ff..87c13353111 100644 --- a/src/doc/fr/tutorial/conf.py +++ b/src/doc/fr/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/fr/tutorial', '{filename}'), +}) + # General information about the project. project = "Tutoriel Sage" name = 'tutorial-fr' diff --git a/src/doc/hu/a_tour_of_sage/conf.py b/src/doc/hu/a_tour_of_sage/conf.py index 90517269f2e..590be9195cb 100644 --- a/src/doc/hu/a_tour_of_sage/conf.py +++ b/src/doc/hu/a_tour_of_sage/conf.py @@ -22,6 +22,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/hu/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = 'A Sage bemutatása' name = 'a_tour_of_sage' diff --git a/src/doc/it/a_tour_of_sage/conf.py b/src/doc/it/a_tour_of_sage/conf.py index f897b790c2a..6d217dee7ec 100644 --- a/src/doc/it/a_tour_of_sage/conf.py +++ b/src/doc/it/a_tour_of_sage/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/it/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = 'Esplora Sage' name = 'a_tour_of_sage' diff --git a/src/doc/it/faq/conf.py b/src/doc/it/faq/conf.py index b5a536d383b..c2cd668d0f8 100644 --- a/src/doc/it/faq/conf.py +++ b/src/doc/it/faq/conf.py @@ -22,6 +22,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/it/faq', '{filename}'), +}) + # General information about the project. project = "Sage FAQ" diff --git a/src/doc/it/tutorial/conf.py b/src/doc/it/tutorial/conf.py index 1f3bdec9367..13bfa100034 100644 --- a/src/doc/it/tutorial/conf.py +++ b/src/doc/it/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/it/tutorial', '{filename}'), +}) + # General information about the project. project = "Tutorial Sage" name = 'tutorial-it' diff --git a/src/doc/ja/a_tour_of_sage/conf.py b/src/doc/ja/a_tour_of_sage/conf.py index 451d7cc5b58..105cae0a93d 100644 --- a/src/doc/ja/a_tour_of_sage/conf.py +++ b/src/doc/ja/a_tour_of_sage/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/ja/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = "Sage ガイドツアー" name = 'a_tour_of_sage' diff --git a/src/doc/ja/tutorial/conf.py b/src/doc/ja/tutorial/conf.py index e4b79bd7875..ef32faab6b8 100644 --- a/src/doc/ja/tutorial/conf.py +++ b/src/doc/ja/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/ja/tutorial', '{filename}'), +}) + # General information about the project. project = "Sage チュートリアル" name = 'tutorial-jp' diff --git a/src/doc/pt/a_tour_of_sage/conf.py b/src/doc/pt/a_tour_of_sage/conf.py index 10d9367f942..075e2d7a4f5 100644 --- a/src/doc/pt/a_tour_of_sage/conf.py +++ b/src/doc/pt/a_tour_of_sage/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/pt/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = 'Uma Turnê pelo Sage' name = 'a_tour_of_sage' diff --git a/src/doc/pt/tutorial/conf.py b/src/doc/pt/tutorial/conf.py index f299582db9a..13582d8b896 100644 --- a/src/doc/pt/tutorial/conf.py +++ b/src/doc/pt/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/pt/tutorial', '{filename}'), +}) + # General information about the project. project = "Tutorial Sage" name = 'tutorial-pt' diff --git a/src/doc/ru/tutorial/conf.py b/src/doc/ru/tutorial/conf.py index cda4d9762ed..5ff38a94d50 100644 --- a/src/doc/ru/tutorial/conf.py +++ b/src/doc/ru/tutorial/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, 'blob/develop/src/doc/ru/tutorial', '{filename}'), +}) + # General information about the project. project = "Sage Tutorial in Russian" name = 'tutorial-ru' diff --git a/src/doc/tr/a_tour_of_sage/conf.py b/src/doc/tr/a_tour_of_sage/conf.py index f969a1b516a..c1854ee2f42 100644 --- a/src/doc/tr/a_tour_of_sage/conf.py +++ b/src/doc/tr/a_tour_of_sage/conf.py @@ -20,6 +20,11 @@ # contains common paths. html_static_path = [] + html_common_static_path +# Add a small edit button. +html_theme_options.update({ + 'source_edit_link': os.path.join(source_repository, f'blob/develop/src/doc/tr/a_tour_of_sage', '{filename}'), +}) + # General information about the project. project = 'Sage Turu' name = 'a_tour_of_sage' diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 039212c53eb..3957598771d 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -3,14 +3,6 @@ This module extends parts of Python's inspect module to Cython objects. -AUTHORS: - -- originally taken from Fernando Perez's IPython -- William Stein (extensive modifications) -- Nick Alexander (extensions) -- Nick Alexander (testing) -- Simon King (some extension for Cython, generalisation of SageArgSpecVisitor) - EXAMPLES:: sage: from sage.misc.sageinspect import * @@ -21,10 +13,8 @@ sage: sage_getfile(sage.rings.rational) '.../rational.pyx' - sage: sage_getdoc(sage.rings.rational).lstrip() 'Rational Numbers...' - sage: sage_getsource(sage.rings.rational) '# distutils: ...Rational Numbers...' @@ -32,10 +22,8 @@ sage: sage_getfile(sage.misc.sageinspect) '.../sageinspect.py' - sage: print(sage_getdoc(sage.misc.sageinspect).lstrip()[:40]) Inspect Python, Sage, and Cython objects - sage: sage_getsource(sage.misc.sageinspect).lstrip()[5:-1] 'Inspect Python, Sage, and Cython objects...' @@ -45,10 +33,8 @@ sage: sage_getfile(sage.rings.rational.Rational) '.../rational.pyx' - sage: sage_getdoc(sage.rings.rational.Rational).lstrip() 'A rational number...' - sage: sage_getsource(sage.rings.rational.Rational) 'cdef class Rational...' @@ -56,10 +42,8 @@ sage: sage_getfile(BlockFinder) '.../sage/misc/sageinspect.py' - sage: sage_getdoc(BlockFinder).lstrip()[:50] - 'Provide a tokeneater() method to detect the...' - + 'Provide a "tokeneater()" method to detect the end ' sage: sage_getsource(BlockFinder) 'class BlockFinder:...' @@ -69,13 +53,10 @@ sage: sage_getdef(sage.rings.rational.make_rational, obj_name='mr') 'mr(s)' - sage: sage_getfile(sage.rings.rational.make_rational) '.../rational.pyx' - sage: sage_getdoc(sage.rings.rational.make_rational).lstrip() 'Make a rational number ...' - sage: sage_getsource(sage.rings.rational.make_rational) '@cython.binding(True)\ndef make_rational(s):...' @@ -83,13 +64,10 @@ sage: sage_getdef(sage.misc.sageinspect.sage_getfile, obj_name='sage_getfile') 'sage_getfile(obj)' - sage: sage_getfile(sage.misc.sageinspect.sage_getfile) '.../sageinspect.py' - sage: sage_getdoc(sage.misc.sageinspect.sage_getfile).lstrip() 'Get the full file name associated to "obj" as a string...' - sage: sage_getsource(sage.misc.sageinspect.sage_getfile)[4:] 'sage_getfile(obj):...' @@ -98,7 +76,6 @@ sage: sage_getdef(''.find, 'find') 'find(*args, **kwds)' - sage: sage_getdef(str.find, 'find') 'find(*args, **kwds)' @@ -112,6 +89,22 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return sage: sage_getargspec(foo) FullArgSpec(args=['x', 'a', 'b'], varargs='args', varkw='kwds', defaults=(1, ')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={}) +AUTHORS: + +- Originally taken from Fernando Perez's IPython +- William Stein: extensive modifications +- William Stein: in :func:`_sage_getargspec_cython`, a modified version of + ``inspect.getargspec`` from the Python Standard Library, which was taken from + IPython for use in Sage +- Nick Alexander: extensions, testing +- Simon King: some extension for Cython, generalisation of SageArgSpecVisitor +- Simon King: in :func:`sage_getsourcelines`, if a class has no docstring then let the + class definition be found starting from the ``__init__`` method. +- Simon King: in :func:`sage_getsourcelines`, get source lines for dynamic classes +- Simon King: in :func:`_sage_getargspec_cython`, return an ``ArgSpec``, fix some bugs +- Simon King (2011-09): added :func:`_sage_getsourcelines_name_with_dot` +- Simon King (2013-02): in :func:`_sage_getargspec_cython`, recognise varargs and + default values in cython code, and return an ``ArgSpec`` """ import ast @@ -200,7 +193,9 @@ def isclassinstance(obj): r""" Check if argument is instance of non built-in class - INPUT: ``obj`` -- object + INPUT: + + - ``obj`` -- object EXAMPLES:: @@ -282,11 +277,6 @@ def _extract_embedded_position(docstring): ....: print(f.read()) cpdef test_funct(x,y): return - AUTHORS: - - - William Stein - - Extensions by Nick Alexander - - Extension for interactive Cython code by Simon King """ try: res = __embedded_position_re.search(docstring) @@ -334,10 +324,6 @@ def _extract_embedded_signature(docstring, name): INPUT: ``docstring`` (string) - AUTHORS: - - - Simon King - EXAMPLES:: sage: from sage.misc.sageinspect import _extract_embedded_signature @@ -349,6 +335,7 @@ def _extract_embedded_signature(docstring, name): FullArgSpec(args=['self', 'x', 'r'], varargs='args', varkw='kwds', defaults=((1, 2, 3.4),), kwonlyargs=[], kwonlydefaults=None, annotations={}) sage: _extract_embedded_signature(range.__call__.__doc__, '__call__') ('Call self as a function.', None) + """ # If there is an embedded signature, it is in the first line L = docstring.split(os.linesep, 1) @@ -370,7 +357,7 @@ def _extract_embedded_signature(docstring, name): class BlockFinder: """ - Provide a tokeneater() method to detect the end of a code block. + Provide a :meth:`tokeneater` method to detect the end of a code block. This is the Python library's :class:`inspect.BlockFinder` modified to recognize Cython definitions. @@ -444,8 +431,8 @@ def _extract_source(lines, lineno): INPUT: - - ``lines`` - string or list of strings - - ``lineno`` - positive integer + - ``lines`` -- string or list of strings + - ``lineno`` -- positive integer EXAMPLES:: @@ -494,6 +481,7 @@ class SageArgSpecVisitor(ast.NodeVisitor): 'jc' sage: visitor.visit(v.value) ['veni', 'vidi', 'vici'] + """ def visit_Name(self, node): """ @@ -501,11 +489,9 @@ def visit_Name(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: + - ``node`` -- the node instance to visit - - None, True, False, or the ``node``'s name as a string. + OUTPUT: ``None``, ``True``, ``False``, or the ``node``'s name as a string EXAMPLES:: @@ -516,6 +502,7 @@ def visit_Name(self, node): ['foo', 'bar'] sage: [type(vis(n)) for n in ['foo', 'bar']] [, ] + """ return node.id @@ -530,9 +517,7 @@ def visit_NameConstant(self, node): - ``node`` - the node instance to visit - OUTPUT: - - - None, True, False. + OUTPUT: ``None``, ``True``, ``False`` EXAMPLES:: @@ -543,6 +528,7 @@ def visit_NameConstant(self, node): [True, False, None] sage: [type(vis(n)) for n in ['True', 'False', 'None']] [, , ] + """ return node.value @@ -560,9 +546,7 @@ def visit_arg(self, node): - ``node`` -- the node instance to visit - OUTPUT: - - the argument name + OUTPUT: the argument name EXAMPLES:: @@ -572,6 +556,7 @@ def visit_arg(self, node): sage: args = ast.parse(s).body[0].args.args sage: [visitor.visit_arg(n) for n in args] ['a', 'b', 'c', 'd'] + """ return node.arg @@ -581,11 +566,9 @@ def visit_Num(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: + - ``node`` -- the node instance to visit - - the number the ``node`` represents + OUTPUT: the number the ``node`` represents EXAMPLES:: @@ -608,11 +591,9 @@ def visit_Str(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: + - ``node`` -- the node instance to visit - - the string the ``node`` represents + OUTPUT: the string the ``node`` represents EXAMPLES:: @@ -621,6 +602,7 @@ def visit_Str(self, node): sage: vis = lambda x: visitor.visit_Str(ast.parse(x).body[0].value) sage: [vis(s) for s in ['"abstract"', "'syntax'", r'''r"tr\ee"''']] ['abstract', 'syntax', 'tr\\ee'] + """ return node.value @@ -630,11 +612,9 @@ def visit_List(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: + - ``node`` -- the node instance to visit - - the list the ``node`` represents + OUTPUT: the list the ``node`` represents EXAMPLES:: @@ -643,6 +623,7 @@ def visit_List(self, node): sage: vis = lambda x: visitor.visit_List(ast.parse(x).body[0].value) sage: [vis(l) for l in ['[]', "['s', 't', 'u']", '[[e], [], [pi]]']] [[], ['s', 't', 'u'], [['e'], [], ['pi']]] + """ t = [] for n in node.elts: @@ -655,11 +636,9 @@ def visit_Tuple(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: + - ``node`` -- the node instance to visit - - the tuple the ``node`` represents + OUTPUT: the tuple the ``node`` represents EXAMPLES:: @@ -668,6 +647,7 @@ def visit_Tuple(self, node): sage: vis = lambda x: visitor.visit_Tuple(ast.parse(x).body[0].value) sage: [vis(t) for t in ['()', '(x,y)', '("Au", "Al", "Cu")']] [(), ('x', 'y'), ('Au', 'Al', 'Cu')] + """ t = [] for n in node.elts: @@ -680,11 +660,9 @@ def visit_Dict(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: + - ``node`` -- the node instance to visit - - the dictionary the ``node`` represents + OUTPUT: the dictionary the ``node`` represents EXAMPLES:: @@ -694,6 +672,7 @@ def visit_Dict(self, node): sage: v = [vis(d) for d in ['{}', "{1:one, 'two':2, other:bother}"]] sage: [sorted(d.items(), key=lambda x: str(x[0])) for d in v] [[], [(1, 'one'), ('other', 'bother'), ('two', 2)]] + """ d = {} for k, v in zip(node.keys, node.values): @@ -706,15 +685,9 @@ def visit_BoolOp(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: - - - The result that ``node`` represents - - AUTHOR: + - ``node`` -- the node instance to visit - - Simon King + OUTPUT: the result that ``node`` represents EXAMPLES:: @@ -745,15 +718,9 @@ def visit_Compare(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: - - - The result that ``node`` represents - - AUTHOR: + - ``node`` -- the node instance to visit - - Simon King + OUTPUT: the result that ``node`` represents EXAMPLES:: @@ -797,15 +764,9 @@ def visit_BinOp(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: - - - The result that ``node`` represents - - AUTHOR: + - ``node`` -- the node instance to visit - - Simon King + OUTPUT: the result that ``node`` represents EXAMPLES:: @@ -814,6 +775,7 @@ def visit_BinOp(self, node): sage: vis = lambda x: visitor.visit(ast.parse(x).body[0].value) sage: [vis(d) for d in ['(3+(2*4))', '7|8', '5^3', '7/3', '7//3', '3<<4']] #indirect doctest [11, 15, 6, 2.3333333333333335, 2, 48] + """ op = node.op.__class__.__name__ if op == 'Add': @@ -867,15 +829,9 @@ def visit_UnaryOp(self, node): INPUT: - - ``node`` - the node instance to visit - - OUTPUT: - - - The result that ``node`` represents - - AUTHOR: + - ``node`` -- the node instance to visit - - Simon King + OUTPUT: the result that ``node`` represents EXAMPLES:: @@ -901,7 +857,7 @@ def _grep_first_pair_of_parentheses(s): INPUT: - A string + - ``s`` -- a string OUTPUT: @@ -924,6 +880,7 @@ def _grep_first_pair_of_parentheses(s): Traceback (most recent call last): ... SyntaxError: The given string does not contain balanced parentheses + """ out = [] single_quote = False @@ -956,7 +913,7 @@ def _split_syntactical_unit(s): INPUT: - - ``s``, a string + - ``s`` -- a string OUTPUT: @@ -1101,12 +1058,10 @@ def _sage_getargspec_from_ast(source): INPUT: - - ``source`` - a string; the function's (or method's) source code + - ``source`` -- a string; the function's (or method's) source code definition. The function's body is ignored. - OUTPUT: - - - an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple + OUTPUT: an instance of :obj:`inspect.ArgSpec`, i.e., a named tuple EXAMPLES:: @@ -1123,6 +1078,7 @@ def _sage_getargspec_from_ast(source): True sage: set(from_ast(sms.sage_getsource(x)) == inspect.getfullargspec(x) for x in [factor, identity_matrix, Graph.__init__]) # needs sage.graphs sage.modules {True} + """ ast_args = ast.parse(source.lstrip()).body[0].args @@ -1146,13 +1102,11 @@ def _sage_getargspec_cython(source): INPUT: - - ``source`` - a string; the function's (or method's) source code + - ``source`` -- a string; the function's (or method's) source code definition. The function's body is ignored. The definition may contain type definitions for the function arguments. - OUTPUT: - - - an instance of :class:`inspect.FullArgSpec`, i.e., a named tuple + OUTPUT: an instance of :class:`inspect.FullArgSpec`, i.e., a named tuple EXAMPLES:: @@ -1222,13 +1176,6 @@ def _sage_getargspec_cython(source): defaults=('a string', {(1, 2, 3): True}), kwonlyargs=[], kwonlydefaults=None, annotations={}) - - AUTHORS: - - - Nick Alexander: original version - - Simon King (02-2013): recognise varargs and default values in - cython code, and return an ``ArgSpec``. - """ defpos = source.find('def ') assert defpos > -1, "The given source does not contain 'def'" @@ -1352,7 +1299,9 @@ def sage_getfile(obj): r""" Get the full file name associated to ``obj`` as a string. - INPUT: ``obj``, a Sage object, module, etc. + INPUT: + + - ``obj`` -- a Sage object, module, etc. EXAMPLES:: @@ -1395,10 +1344,6 @@ def sage_getfile(obj): sage: sage_getfile(range) '' - AUTHORS: - - - Nick Alexander - - Simon King """ # We try to extract from docstrings, but not using Python's inspect # because _sage_getdoc_unformatted is more robust. @@ -1433,7 +1378,9 @@ def sage_getfile_relative(obj): if the source file is part of the ``sage.*`` namespace, it makes the file name relative so that it starts with ``sage/``. - INPUT: ``obj``, a Sage object, module, etc. + INPUT: + + - ``obj`` -- a Sage object, module, etc. EXAMPLES:: @@ -1447,6 +1394,7 @@ def sage_getfile_relative(obj): 'sage/symbolic/expression.pyx' sage: sage_getfile_relative(range) '' + """ filename = sage_getfile(obj) if not filename: @@ -1669,12 +1617,6 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return sage: shell.run_cell('f??') ...the source code string... - AUTHORS: - - - William Stein: a modified version of inspect.getargspec from the - Python Standard Library, which was taken from IPython for use in Sage. - - Extensions by Nick Alexander - - Simon King: Return an ``ArgSpec``, fix some bugs. """ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.abstract_method import AbstractMethod @@ -1773,7 +1715,7 @@ def formatannotation(annotation, base_module=None): INPUT: - ``annotation`` -- annotation for a function - - ``base_module`` (optional, default ``None``) + - ``base_module``-- (optional, default ``None``) This is only relevant with Python 3, so the doctests are marked accordingly. @@ -1895,8 +1837,8 @@ def sage_getdef(obj, obj_name=''): INPUT: - - ``obj`` - function - - ``obj_name`` - string (optional, default '') + - ``obj`` -- function + - ``obj_name`` -- string (optional, default '') ``obj_name`` is prepended to the output. @@ -1915,11 +1857,6 @@ def sage_getdef(obj, obj_name=''): If an exception is generated, None is returned instead and the exception is suppressed. - - AUTHORS: - - - William Stein - - extensions by Nick Alexander """ try: spec = sage_getargspec(obj) @@ -1985,10 +1922,6 @@ def _sage_getdoc_unformatted(obj): sage: _sage_getdoc_unformatted(obj) '' - AUTHORS: - - - William Stein - - extensions by Nick Alexander """ if obj is None: return '' @@ -2126,10 +2059,6 @@ def sage_getdoc(obj, obj_name='', embedded=False): sage: sage_getdoc(f1) 'specialised documentation\n' - AUTHORS: - - - William Stein - - extensions by Nick Alexander """ import sage.misc.sagedoc if obj is None: @@ -2170,11 +2099,6 @@ def sage_getsource(obj): 'identity_matrix(ring, n=0, sparse=False):' sage: sage_getsource(identity_matrix)[19:60] # needs sage.modules 'identity_matrix(ring, n=0, sparse=False):' - - AUTHORS: - - - William Stein - - extensions by Nick Alexander """ # First we should check if the object has a _sage_src_ # method. If it does, we just return the output from @@ -2236,10 +2160,6 @@ class ParentMethods: has a docstring. Otherwise, the code of ``B`` could not be found (Cython inserts embedding information into the docstring) and thus the code of ``B.A`` couldn't be found either. - - AUTHOR: - - - Simon King (2011-09) """ # First, split the name: if '.' in obj.__name__: @@ -2347,26 +2267,30 @@ def sage_getsourcelines(obj): EXAMPLES:: sage: from sage.misc.sageinspect import sage_getsourcelines - sage: from sage.matrix.constructor import matrix # needs sage.modules - sage: sage_getsourcelines(matrix)[1] # needs sage.modules + + sage: # needs sage.modules + sage: from sage.matrix.constructor import matrix + sage: sage_getsourcelines(matrix)[1] 21 - sage: sage_getsourcelines(matrix)[0][0] # needs sage.modules + sage: sage_getsourcelines(matrix)[0][0] 'def matrix(*args, **kwds):\n' Some classes customize this using a ``_sage_src_lines_`` method, which gives the source lines of a class instance, but not the class itself. We demonstrate this for :class:`CachedFunction`:: - sage: cachedfib = cached_function(fibonacci) # needs sage.combinat - sage: sage_getsourcelines(cachedfib)[0][0] # needs sage.combinat + sage: # needs sage.combinat + sage: cachedfib = cached_function(fibonacci) + sage: sage_getsourcelines(cachedfib)[0][0] 'def fibonacci(n, algorithm="pari") -> Integer:\n' - sage: sage_getsourcelines(type(cachedfib))[0][0] # needs sage.combinat + sage: sage_getsourcelines(type(cachedfib))[0][0] 'cdef class CachedFunction():\n' TESTS:: - sage: cython('''cpdef test_funct(x,y): return''') # needs sage.misc.cython - sage: sage_getsourcelines(test_funct) # needs sage.misc.cython + sage: # needs sage.misc.cython + sage: cython('''cpdef test_funct(x,y): return''') + sage: sage_getsourcelines(test_funct) (['cpdef test_funct(x,y): return\n'], 1) The following tests that an instance of ``functools.partial`` is correctly @@ -2444,14 +2368,6 @@ class Element(): ' def __init__(self, ring, gens, coerce=True):\n', ...) - AUTHORS: - - - William Stein - - Extensions by Nick Alexander - - Extension to interactive Cython code by Simon King - - Simon King: If a class has no docstring then let the class - definition be found starting from the ``__init__`` method. - - Simon King: Get source lines for dynamic classes. """ # First try the method _sage_src_lines_(), which is meant to give # the source lines of an object (not of its type!). @@ -2491,11 +2407,7 @@ class Element(): pos = _extract_embedded_position(d) if pos is None: try: - # BEWARE HERE - # inspect gives str (=bytes) in python2 - # and str (=unicode) in python3 return inspect.getsourcelines(obj) - except (OSError, TypeError) as err: try: objinit = obj.__init__ diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 1c705c68d1f..99b7dfe0927 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -18,24 +18,23 @@ # Load configuration shared with sage.misc.sphinxify from sage.misc.sagedoc_conf import * -import importlib import sys import os +import importlib +import dateutil.parser import sphinx import sphinx.ext.intersphinx as intersphinx -import dateutil.parser -import sage.version - from sphinx import highlighting from sphinx.transforms import SphinxTransform from IPython.lib.lexers import IPythonConsoleLexer, IPyLexer - from sage.misc.sagedoc import extlinks from sage.env import SAGE_DOC_SRC, SAGE_DOC, PPLPY_DOCS, MATHJAX_DIR from sage.misc.latex_macros import sage_mathjax_macros from sage.features import PythonModule from sage.features.all import all_features +import sage.version +# --------------------- # General configuration # --------------------- @@ -51,6 +50,7 @@ 'sphinx.ext.todo', 'sphinx.ext.extlinks', 'sphinx.ext.mathjax', + 'sphinx.ext.linkcode', 'sphinx_copybutton', 'sphinx_inline_tabs', 'IPython.sphinxext.ipython_directive', @@ -198,6 +198,9 @@ def sphinx_plot(graphics, **kwds): version = sage.version.version release = sage.version.version +source_repository = 'https://github.com/sagemath/sage/' +source_branch = 'develop' + # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None @@ -255,6 +258,7 @@ def sphinx_plot(graphics, **kwds): # displaying all parents. toc_object_entries_show_parents = 'hide' +# ----------------------- # Extension configuration # ----------------------- @@ -313,73 +317,116 @@ def set_intersphinx_mappings(app, config): copybutton_exclude = '.linenos, .c1' # exclude single comments (in particular, # optional!) copybutton_only_copy_prompt_lines = True + +# https://www.sphinx-doc.org/en/master/usage/extensions/linkcode.html +def linkcode_resolve(domain, info): + import inspect + from urllib.parse import quote + from sage.misc.sageinspect import sage_getsourcelines + if domain != 'py': + return None + if info['module']: + m = importlib.import_module(info['module']) + filename = quote(info['module'].replace('.', '/')) + if m.__file__.endswith('py'): + filename += '.py' + else: + filename += '.pyx' + if 'fullname' in info: + fullname = info['fullname'] + obj = m + try: + for attr in fullname.split('.'): + obj = getattr(obj, attr) + lineno = sage_getsourcelines(obj)[-1] + except Exception: # catch all + return None + anchor = f'#L{lineno}' + else: + anchor = '' + return f"{source_repository}blob/{version}/src/{filename}{anchor}" + return None + + +# ----------------------- # Options for HTML output # ----------------------- # Add any paths that contain custom themes here, relative to this directory. html_theme_path = [os.path.join(SAGE_DOC_SRC, "common", "themes")] -if PythonModule("furo").is_present(): - # Sphinx theme "furo" does not permit an extension. Do not attempt to make - # a "sage-furo" theme. - html_theme = "furo" - - # Theme options are theme-specific and customize the look and feel of - # a theme further. For a list of options available for each theme, - # see the documentation. - html_theme_options = { - "light_css_variables": { - "color-brand-primary": "#0f0fff", - "color-brand-content": "#0f0fff", - }, - "light_logo": "logo_sagemath_black.svg", - "dark_logo": "logo_sagemath_white.svg", - } - - # The name of the Pygments (syntax highlighting) style to use. This - # overrides a HTML theme's corresponding setting. - pygments_style = "sphinx" - pygments_dark_style = "monokai" - - # Add siderbar/home.html to the default sidebar. - html_sidebars = { - "**": [ - "sidebar/scroll-start.html", - "sidebar/brand.html", - "sidebar/search.html", - "sidebar/home.html", - "sidebar/navigation.html", - "sidebar/ethical-ads.html", - "sidebar/scroll-end.html", - "sidebar/variant-selector.html", - ] - } - - # These paths are either relative to html_static_path - # or fully qualified paths (eg. https://...) - html_css_files = [ - 'custom-furo.css', - 'custom-jupyter-sphinx.css', - 'custom-codemirror-monokai.css', - ] +# Deprecated Sage classic theme: +# +# html_theme = "sage-classic" +# html_theme_options = {} +# +# See the directory doc/common/themes/sage-classic/ for theme files. + +# Sphinx theme "furo" does not permit an extension. Do not attempt to make +# a "sage-furo" theme. +html_theme = "furo" + +# Theme options are theme-specific and customize the look and feel of +# a theme further. For a list of options available for each theme, +# see the documentation. +html_theme_options = { + "light_css_variables": { + "color-brand-primary": "#0f0fff", + "color-brand-content": "#0f0fff", + }, + "light_logo": "logo_sagemath_black.svg", + "dark_logo": "logo_sagemath_white.svg", + # Furo can add a small edit button to each document to allow visitors to + # easily propose changes to that document using the repository’s source + # control system. + # https://pradyunsg.me/furo/customisation/edit-button/#adding-an-edit-button + "source_repository": source_repository, + "source_branch": source_branch, + # "source_directory" is defined in conf.py customized for the doc +} - html_js_files = [ - 'jupyter-sphinx-furo.js', +if not version.split('.')[-1].isnumeric(): # develop version + html_theme_options.update({ + "announcement": f'This is documentation for Sage development version {version}. ' + 'The documentation for the latest stable version is available ' + 'here.' +}) + +# The name of the Pygments (syntax highlighting) style to use. This +# overrides a HTML theme's corresponding setting. +pygments_style = "sphinx" +pygments_dark_style = "monokai" + +# Add siderbar/home.html to the default sidebar. +html_sidebars = { + "**": [ + "sidebar/scroll-start.html", + "sidebar/brand.html", + "sidebar/search.html", + "sidebar/home.html", + "sidebar/navigation.html", + "sidebar/ethical-ads.html", + "sidebar/scroll-end.html", + "sidebar/variant-selector.html", ] +} - # A list of paths that contain extra templates (or templates that overwrite - # builtin/theme-specific templates). Relative paths are taken as relative - # to the configuration directory. - templates_path = [os.path.join(SAGE_DOC_SRC, 'common', 'templates-furo')] + templates_path +# These paths are either relative to html_static_path +# or fully qualified paths (eg. https://...) +html_css_files = [ + 'custom-furo.css', + 'custom-jupyter-sphinx.css', + 'custom-codemirror-monokai.css', +] -else: - # Sage default Sphinx theme. - # - # See the directory doc/common/themes/sage-classic/ for files comprising - # the custom theme. - html_theme = "sage-classic" +html_js_files = [ + 'jupyter-sphinx-furo.js', +] - html_theme_options = {} +# A list of paths that contain extra templates (or templates that overwrite +# builtin/theme-specific templates). Relative paths are taken as relative +# to the configuration directory. +templates_path = [os.path.join(SAGE_DOC_SRC, 'common', 'templates-furo')] + templates_path # HTML style sheet. This overrides a HTML theme's corresponding setting. # html_style = 'default.css' @@ -438,7 +485,7 @@ def set_intersphinx_mappings(app, config): # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. @@ -460,27 +507,29 @@ def set_intersphinx_mappings(app, config): modindex_common_prefix = ['sage.'] # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. html_split_index = True # If true, the reST sources are included in the HTML build as _sources/. -#html_copy_source = True +# html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# html_file_suffix = '' # Output file base name for HTML help builder. -#htmlhelp_basename = '' +# htmlhelp_basename = '' +# ------------------------ # Options for LaTeX output # ------------------------ + # See http://sphinx-doc.org/config.html#confval-latex_elements latex_elements = {} @@ -523,13 +572,14 @@ def set_intersphinx_mappings(app, config): """ # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +# latex_use_modindex = True -##################################################### +# ------------------------- # add LaTeX macros for Sage +# ------------------------- from sage.misc.latex_macros import sage_latex_macros @@ -544,8 +594,9 @@ def set_intersphinx_mappings(app, config): # used when building html version pngmath_latex_preamble += macro + '\n' -##################################################### +# ------------------------------------------ # add custom context variables for templates +# ------------------------------------------ def add_page_context(app, pagename, templatename, context, doctree): # # The template function @@ -569,6 +620,17 @@ def add_page_context(app, pagename, templatename, context, doctree): context['reference_title'] = 'Sage {}'.format(release) + ' Reference Manual' context['reference_root'] = os.path.join(relpath, 'index.html') context['refsub'] = True + if pagename.startswith('sage/'): + # This is for adding small edit button using Furo's feature: + # https://pradyunsg.me/furo/customisation/edit-button/#adding-an-edit-button + # This works well if the source file is '.rst' file. But the '.rst' + # files in the directory 'sage/' are generated by the Sphinx + # autodoc from the Python or Cython source files. Hence we teak + # here template context variables so that links to the correct + # source files are generated. + suffix = '.py' if importlib.import_module(pagename.replace('/','.')).__file__.endswith('.py') else '.pyx' + context['page_source_suffix'] = suffix + context['theme_source_edit_link'] = os.path.join(source_repository, f'blob/develop/src', '{filename}') dangling_debug = False @@ -731,7 +793,6 @@ def nitpick_patch_config(app): '__builtin__', ] - def check_nested_class_picklability(app, what, name, obj, skip, options): """ Print a warning if pickling is broken for nested classes.