一般公约

有许多方法可以为Sage做出贡献,包括共享脚本和使用Sage实现新功能的Jupyter笔记本、改进Sage库或使用随Sage分发的许多底层库,请参见 spkg 。本指南重点介绍编辑Sage库本身。

SAGE不仅仅是将功能聚集在一起。它是关于提供一种清晰、系统和一致的方法来访问大量算法,在一个在数学上有意义的连贯框架中。在Sage的设计中,对象的语义、定义等都是通过相应的对象在日常数学中的使用方式来提供信息的。

为了实现使Sage易于阅读、维护和改进的目标,Sage附带的所有Python/Cython代码都应该遵循本章中讨论的样式约定。

Python代码样式

在为Sage编写代码时,请遵循标准的Python格式规则,如以下URL中所述:

特别是,

  • 使用4个空格表示缩进级别。不要使用制表符,因为它们可能会导致缩进混乱。大多数编辑器都有一项功能,当按下 Tab 按下了键。此外,许多编辑程序会自动搜索/替换带有4个空格的前导制表符。

  • 赋值前后的空格和表达式中优先级最低的二元运算符::

    i = i + 1
    c = (a+b) * (a-b)
    
  • 之前或之后没有空格。 = 用于关键字参数的签名::

    def complex(real, imag=0.0):
        return magic(r=real, i=imag)
    
  • 圆括号、方括号和大括号内没有空格::

    spam(ham[1], {eggs: 2})
    [i^2 for i in range(3)]
    
  • 使用所有小写的函数名称,单词之间用下划线隔开。例如,我们鼓励您使用以下命名约定编写Python函数:

    def set_some_value():
        return 1
    

    但是,请注意,有些函数在有意义的地方使用大写字母。例如,通过LLL算法进行点阵约简的函数被调用 Matrix_integer_dense.LLL

  • 使用CamelCase作为类名::

    class SomeValue():
        def __init__(self, x):
        self._x  = 1
    

    以及模仿对象构造函数的工厂函数,例如 PolynomialRing 或:

    def SomeIdentityValue(x):
        return SomeValue(1)
    

文件和目录结构

粗略地说,Sage目录树的布局如下。请注意,我们使用 SAGE_ROOT 以下是包含Sage源的目录名称的快捷方式:

SAGE_ROOT/
    sage          # the Sage launcher
    Makefile      # top level Makefile
    build/        # Sage's build system
        pkgs/     # install, patch, and metadata from spkgs
    src/
        setup.py
        ...
        sage/            # Sage library
            ext_data/    # extra Sage resources (legacy)
        bin/             # the scripts in local/bin that are tracked
    upstream/            # tarballs of upstream sources
    local/               # installed binaries

Python Sage库代码进入 src/sage/ 并使用以下约定。目录名称可以是复数(例如 rings )和文件名几乎总是单数(例如 polynomial_ring.py )。请注意,文件 polynomial_ring.py 可能仍然包含几种不同类型的多项式环的定义。

备注

我们鼓励您在包裹中包含各种笔记、电子邮件、设计讨论等内容。制作这些纯文本文件(带扩展名 .txt )在名为的子目录中 notes

如果要创建新目录 (package )在Sage库中 SAGE_ROOT/src/sage (比如说, measure_theory ),则该目录通常包含一个空文件 __init__.py ,它将目录标记为普通程序包(请参见 普通包与隐式命名空间包 ),还有一个文件 all.py 列出了来自该包的导入,这些导入是面向用户的,并且足够重要,在启动时位于Sage的全局名称空间中。档案 all.py 可能如下所示::

from .borel_measure import BorelMeasure
from .banach_tarski import BanachTarskiParadox

但一般情况下,使用 lazy_import 框架::

from sage.misc.lazy_import import lazy_import
lazy_import('sage.measure_theory.borel_measure', 'BorelMeasure')
lazy_import('sage.measure_theory.banach_tarski', 'BanachTarskiParadox')

然后在文件中 SAGE_ROOT/src/sage/all.py ,添加一行::

from sage.measure_theory.all import *

在下面添加新的顶级程序包 sage 应该慎重行事。创建现有包的子包通常更好。

可以在以下位置之一包含非Python Sage源代码和小型支持文件:

  • 在使用该文件的Python代码的目录中。安装Sage库时,该文件将安装在与Python代码相同的位置。这被称为“包数据”。

    从Python访问数据的首选方式是使用 importlib.resources API ,特别是该函数 importlib.resources.files() 。使用它,您可以:

    • 打开用于文本阅读的资源: fd = files(package).joinpath(resource).open('rt')

    • 打开用于二进制读取的资源: fd = files(package).joinpath(resource).open('rb')

    • 将资源作为文本阅读: text = files(package).joinpath(resource).read_text()

    • 以字节为单位读取资源: bytes = files(package).joinpath(resource).read_bytes()

    • 打开XZ压缩资源进行文本阅读: fd = lzma.open(files(package).joinpath(resource).open('rb'), 'rt')

    • 打开用于二进制读取的XZ压缩资源: fd = lzma.open(files(package).joinpath(resource).open('rb'), 'rb')

    如果需要在Python外部使用该文件,则首选方法是使用上下文管理器 importlib.resources.as_file() 。它应该以与上面所示相同的方式导入。

  • Sage库中较旧的代码以更直接的方式访问包数据。例如, SAGE_ROOT/src/sage/interfaces/maxima.py 使用该文件 SAGE_ROOT/src/sage/interfaces/maxima.lisp 在运行时,因此它将其称为::

    os.path.join(os.path.dirname(__file__), 'sage-maxima.lisp')
    
  • 在的相应子目录中 SAGE_ROOT/src/sage/ext_data/ 。(在运行时,它随后在由指示的目录中可用 SAGE_EXTCODE )。例如,如果 file 被放置在 SAGE_ROOT/src/sage/ext_data/directory/ 可通过以下方式访问:

    from sage.env import SAGE_EXTCODE
    file = os.path.join(SAGE_EXTCODE, 'directory', 'file')
    

    此做法已弃用,请参见 :issue:`33037`

在所有情况下,文件都必须(显式或通过通配符)在部分中列出 options.package_data 该文件的 SAGE_ROOT/pkgs/sagemath-standard/setup.cfg.m4 (或另一个发行版的相应文件)。

不应将大型数据文件添加到Sage源树中。取而代之的是,建议做以下工作:

  • 创建一个单独的Git存储库并将它们上传到那里 [2],

  • 将元数据添加到存储库,使其成为PIP可安装的包(分发包),如 Python Packaging User Guide

  • upload it to PyPI <https://packaging.python.org/en/latest/tutorials/packaging-projects/#uploading-the-distribution-archives> _,

  • 在中创建元数据 SAGE_ROOT/build/pkgs 使您的新的pip可安装包为Sage所知;请参见 为SAGE打包第三方代码

有关托管大型数据文件的外部存储库的指导性示例,请参见https://github.com/sagemath/conway-polynomials,和https://github.com/gmou3/matroid-database.

在复制/粘贴中学习

对于这里讨论的所有约定,您可以在Sage库中找到许多示例。浏览代码很有帮助,但搜索也很有帮助:函数 search_srcsearch_def ,以及 search_doc 都是值得了解的。简单地说,从“Sage:”的提示来看, search_src(string) 在Sage库代码中搜索该字符串 string 。该命令 search_def(string) 执行类似的搜索,但仅限于函数定义,而 search_doc(string) 搜索Sage文档。有关更多信息和更多选项,请参阅他们的文档字符串。

Sage库代码文件的标题

每个Sage代码文件的顶部应遵循以下格式::

r"""
<Short one-line summary that ends with no period>

<Paragraph description>

EXAMPLES::

<Lots and lots of examples>

AUTHORS:

- YOUR NAME (2005-01-03): initial version

- person (date in ISO year-month-day format): short desc

"""

# ****************************************************************************
#       Copyright (C) 2013 YOUR NAME <your email>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#                  https://www.gnu.org/licenses/
# ****************************************************************************

作为示例,请参见 SAGE_ROOT/src/sage/rings/integer.pyx ,它包含以下实现 ZZ 。对该文件做出重大贡献的人员的名字出现在 AUTHORS 一节。如果你属于人民,你可以把你的名字加到名单上,但不要在描述中冗长。这个 AUTHORS 部分显示了历史的粗略概述,特别是在很多人一直在处理该源文件的情况下。谁编写了始终是GIT存储库的权威日志(请参见 git blame )。

Sage附带的所有代码必须在GPLv2+或兼容的许可证(即限制性较低的许可证)下获得许可(例如BSD许可证)。

文档字符串

函数的文档字符串:Content

Every 函数必须具有包含以下信息的文档字符串。您可以使用Sage的现有函数作为模板。

  • A one-sentence description 该函数的。

    它后面必须跟一个空行,并以句点结尾。它将函数或方法的效果描述为命令(“执行此操作”、“返回那个”),而不是像“返回路径名...”这样的描述。

    对于类的方法,建议参考 self 以描述性的方式进行论证,除非这会导致混淆。例如,如果 self 是一个整数,那么 this integerthe integer 更具描述性,最好写成

    Return whether this integer is prime.
    
  • A longer description

    如果一句话的描述不需要更多的解释,这是可选的。

    从假设对象开始,如果有任何假设的话。例如,

    The poset is expected to be ranked.
    

    如果函数在对未排名的偏序集调用时引发异常。

    定义您的术语

    The lexicographic product of `G` and `H` is the graph with vertex set ...
    

    并提到可能的别名

    The tensor product is also known as the categorical product and ...
    
  • 一个 INPUT 和一个 OUTPUT 描述函数的输入/输出的块。

    INPUT块描述函数接受的所有参数。

    1. 类型名称应该是描述性的,但不必表示确切的Sage/Python类型。例如,对于行为类似于整数的任何内容,请使用“INTEGER”,而不是 int

    2. 如果适用,请提及输入参数的默认值。

    INPUT:
    
    - ``n`` -- integer
    
    - ``p`` -- prime integer (default: `2`); coprime with ``n``
    

    OUTPUT块描述预期输出。如果功能的一句话描述需要更多说明,则需要执行此操作。

    OUTPUT: the plaintext decrypted from the ciphertext ``C``
    

    通常情况下,输出由几个项目组成。

    OUTPUT: a tuple of
    
    - the reduced echelon form `H` of the matrix `A`
    
    - the transformation matrix `U` such that `UA = H`
    

    对于复杂的输出,建议您足够详细。

    OUTPUT:
    
    The decomposition of the free module on which this matrix `A` acts from
    the right (i.e., the action is `x` goes to `xA`), along with whether
    this matrix acts irreducibly on each factor. The factors are guaranteed
    to be sorted in the same way as the corresponding factors of the
    characteristic polynomial.
    
  • 一个 EXAMPLES 块作为示例。这不是可选的。

    这些示例用于文档,但它们也在每次发布之前进行测试,就像测试块一样。

    他们应该对有问题的功能进行很好的覆盖。

  • A SEEALSO 阻止(强烈推荐),并链接到Sage的相关部分。这有助于用户找到他们感兴趣的功能,并发现新的功能。

    .. SEEALSO::
    
        :ref:`chapter-sage_manuals_links`,
        :meth:`sage.somewhere.other_useful_method`,
        :mod:`sage.some.related.module`.
    

    看见 超链接 有关如何在Sage中设置链接的详细信息。

  • 一个 ALGORITHM 阻止(可选)。

    它指示使用什么算法和/或什么软件,例如 ALGORITHM: Uses Pari 。下面是一个更长的例子,并附有参考书目:

    ALGORITHM:
    
    The following algorithm is adapted from page 89 of [Nat2000]_.
    
    Let `p` be an odd (positive) prime and let `g` be a generator
    modulo `p`. Then `g^k` is a generator modulo `p` if and only if
    `\gcd(k, p-1) = 1`. Since `p` is an odd prime and positive, then
    `p - 1` is even so that any even integer between 1 and `p - 1`,
    inclusive, is not relatively prime to `p - 1`. We have now
    narrowed our search to all odd integers `k` between 1 and `p - 1`,
    inclusive.
    
    So now start with a generator `g` modulo an odd (positive) prime
    `p`. For any odd integer `k` between 1 and `p - 1`, inclusive,
    `g^k` is a generator modulo `p` if and only if `\gcd(k, p-1) = 1`.
    

    书目参考应该放在Sage的主书目档案中, SAGE_ROOT/src/doc/en/reference/references/index.rst

    .. [Nat2000] \M. B. Nathanson. Elementary Methods in Number Theory.
       Springer, 2000.
    
  • A NOTE 屏蔽提示/技巧(可选)。

    .. NOTE::
    
        You should note that this sentence is indented at least 4
        spaces. Never use the tab character.
    
  • A WARNING 块以获取有关代码的关键信息(可选)。

    例如代码中断的已知情况,或用户应该知道的任何事情。

    .. WARNING::
    
        Whenever you edit the Sage documentation, make sure that
        the edited version still builds. That is, you need to ensure
        that you can still build the HTML and PDF versions of the
        updated documentation. If the edited documentation fails to
        build, it is very likely that you would be requested to
        change your patch.
    
  • A TODO 阻止以后的改进(可选)。

    它可以包含禁用的文档测试,以演示所需的功能。下面是一个TODO块的示例:

    .. TODO::
    
        Add to ``have_fresh_beers`` an interface with the faster
        algorithm "Buy a Better Fridge" (BaBF)::
    
            sage: have_fresh_beers('Bière de l\'Yvette', algorithm="BaBF") # not implemented
            Enjoy !
    
  • A PLOT 块来用图片说明函数的输出。

    使用Sage代码生成对象 g 使用一个 .plot 方法,然后调用 sphinx_plot(g)

    .. PLOT::
    
        g = graphs.PetersenGraph()
        sphinx_plot(g)
    
  • A REFERENCES 方块列出相关书籍或论文(可选)。

    几乎所有的书目信息都应该放在主书目档案中,见下文。然后引文将链接到主书目,读者可以在那里找到书目详细信息(参见下文中的引文语法)。因此,单个文档字符串中的参考块通常不是必需的。

    然而,如果存在文档字符串中未明确提及的相关来源,或者如果文档字符串特别长,则引用块可能是有用的。在这种情况下,将书目信息添加到主书目文件(如果尚未存在),并将引用块添加到您的文档字符串,如下所示:

    REFERENCES:
    
    For more information, see [Str1969]_, or one of the following references:
    
    - [Sto2000]_
    
    - [Voe2003]_
    

    注意尾随的下划线,它使引文成为超链接。有关主书目文件的更多信息,请参见下文。有关引用的更多信息,请参阅 Sphinx/reST markup for citations 。有关GitHub问题和PR或维基百科的链接,请参阅 超链接

  • A TESTS 阻止(强烈推荐)。

    格式类似于示例,包含与用户无关的测试。特别是,当用户通过请求帮助时,这些块不会显示 foo? :它们被函数剥离 sage.misc.sagedoc.skip_TESTS_block()

    特殊的和角落的情况,如数字零,一元组等,通常应该放在这个区块。这也是大多数输入验证测试的合适位置;例如,如果函数接受 direction='up'direction='down' ,您可以使用此块来检查 direction='junk' 引发异常。

    出于删除的目的,“test”块是以“test:”(或两个冒号相同)开始的块,单独在一行上,以缩进小于“test”的行结束,或者以缩进级别相同的行--不超过缩进级别--匹配以下任一项:

    • 格式为“..foo:”的Sphinx指令,可选择后跟其他文本。

    • “UPERCASE:”形式的文本,可选择后跟其他文本。

    • 看起来像REST页眉的行:一行包含任何内容,后跟只包含空格的行,后跟一串连字符、等号或其他字符,这些字符是REST页眉的有效标记: - = ` : ' " ~ _ ^ * + # < > 。但是,只包含双冒号的行 :: 不要结束“测试”块。

    有时(但很少)有私有或受保护的方法不需要适当的 EXAMPLES 医生测试。在这些情况下,可以使用 TESTS 阻止或使用pytest来测试该方法。在后一种情况下,必须添加 TESTS: pytest 设置为文档字符串,以便将该方法显式标记为已测试。

关于Sphinx指令与其他块的说明

Sage中使用的主要Sphinx指令包括:

.. MATH::.. NOTE::.. PLOT::.. RUBRIC::.. SEEALSO::.. TODO::.. TOPIC::.. WARNING::

它们必须完全按照上面的方式编写,例如 WARNING::.. WARNING :: 不会奏效的。

也有一些其他指令可用,但使用频率较低,即:

.. MODULEAUTHOR::.. automethod::.. autofunction::.. image::.. figure::

其他块不应用作指令;例如 .. ALGORITHM:: 将根本不会显示。

SAGE文档样式

所有的Sage文档都是用reStrutiredText(REST)编写的,并由Sphinx处理。有关介绍,请参阅https://www.sphinx-doc.org/rest.html。Sage强加了以下风格:

  • 行数应少于80个字符。如果有疑问,请阅读 PEP8: Maximum Line Length

  • 所有REST和Sphinx指令(如 .. WARNING::.. NOTE::.. MATH:: 等)都是用大写字母写的。

  • 代码片段用双反引号引起来。这包括函数参数和类似于 ``True   ````False   ````None ``。例如:

    If ``check`` is ``True``, then ...
    

Sage的师父 BIBLIOGRAPHY 文件

所有参考书目应存储在主书目文件中, SAGE_ROOT/src/doc/en/reference/references/index.rst ,格式为

.. [Gau1801] \C. F. Gauss, *Disquisitiones Arithmeticae*, 1801.

.. [RSA1978] \R. Rivest, A. Shamir, L. Adleman,
             "A Method for Obtaining Digital Signatures and
             Public-Key Cryptosystems".
             Communications of the ACM **21** (February 1978),
             120–126. :doi:`10.1145/359340.359342`.

括号中的部分是引文关键字:给出这些示例,然后可以使用 [Gau1801]_ 在文档字符串中提供指向第一个引用的链接。注意尾部的下划线,它使引文成为一个超链接。

如果可能,关键字应该是这样的形式:对于单个作者,使用姓氏的前三个字母,然后是年份;对于多个作者,使用每个姓氏的第一个字母,然后是年份。请注意,年份应该是四位数,而不仅仅是最后两位--例如,Sage已经引用了1910年和2010年的年份。

在书目列表中缩写作者的名字时,一定要在前面加一个反斜杠。这确保了信件 (C. 在上面的例子中)不会被解释为列表枚举器。

有关引用的更多信息,请参阅 Sphinx/reST markup for citations

模板

在记录函数时,请使用以下模板。请注意缩进:

def point(self, x=1, y=2):
    r"""
    Return the point `(x^5,y)`.

    INPUT:

    - ``x`` -- integer (default: `1`); the description of the
      argument ``x`` goes here. If it contains multiple lines, all
      the lines after the first need to begin at the same indentation
      as the backtick.

    - ``y`` -- integer (default: `2`); the description of the
      argument ``y``

    OUTPUT: the point as a tuple

    EXAMPLES:

    This example illustrates ... ::

        sage: A = ModuliSpace()
        sage: A.point(2,3)
        xxx

    We now ... ::

        sage: B = A.point(5,6)
        sage: xxx

    It is an error to ... ::

        sage: C = A.point('x',7)
        Traceback (most recent call last):
        ...
        TypeError: unable to convert 'r' to an integer

    .. NOTE::

        This function uses the algorithm of [BCDT2001]_ to determine
        whether an elliptic curve `E` over `Q` is modular.

    ...

    .. SEEALSO::

        :func:`line`

    TESTS::

        sage: A.point(42, 0)  # Check for corner case y=0
        xxx
    """
    <body of the function>

主书目文件将包含

.. [BCDT2001] Breuil, Conrad, Diamond, Taylor,
              "Modularity ...."

强烈建议您:

  • 使用LaTeX排版(请参见 Latex 排版 )。

  • 使用原始字符串 (r"""...""" ),而不管文档字符串当前是否包含任何反斜杠。

  • 大方地描述一下这些例子的作用。

    备注

    示例代码之后和下一个示例的说明性文本之前必须有一个空行(缩进是不够的)。

  • 用示例说明该函数引发的异常(如上所述:“这是一个错误 [..] “,...)

  • 包括许多例子。

    它们对用户很有帮助,对Sage的质量和适应性至关重要。如果没有这样的例子,对Sage的一个部分进行的微小更改可能要到很久以后有人使用该系统时才会看到,这是不可接受的。

风格细枝末节

Sage开发人员在编写代码和文档字符串时,应遵循本手册中建议的样式,但有充分理由的特殊情况除外。然而,作为一个社区,我们在一些细节上没有就官方风格达成一致。这些是

  • 一个空格::

    This is the first sentence. This is the second sentence.
    

    对比两个空格::

    This is the first sentence.  This is the second sentence.
    

    两句话之间。

  • 紧凑的名单::

    - first item
    - second item
    - third item
    

    VS间隔列表::

    - first item
    
    - second item
    
    - third item
    

其中每一个都有不同的观点,实际上,我们在我们的代码库中找到了每种风格的实例。那我们该怎么办呢?我们是通过投票决定一种风格的吗?甚至对该怎么做也有不同的意见!

我们至少可以这样做,以防止任何关于这些风格冲突的争议:

  • 承认不同的作者可能对这些有不同的偏好。

  • 尊重第一个编写代码或文档字符串的作者的样式选择。

私人职能

名称以下划线开头的函数被视为私有函数。它们不会出现在参考手册中,它们的文档字符串不应包含对Sage用户至关重要的任何信息。您可以使它们的文档字符串成为另一种方法的文档的一部分。例如::

class Foo(SageObject):

    def f(self):
        """
        <usual docstring>

        .. automethod:: _f
        """
        return self._f()

    def _f(self):
         """
         This would be hidden without the ``.. automethod::``
         """

私有函数应该包含一个示例(或测试)块。

一个特例是构造函数 __init__ :由于其特殊的地位, __init__ 如果还没有DocString类,则将其用作DocString类。也就是说,您可以执行以下操作:

sage: class Foo(SageObject):
....:     # no class docstring
....:     def __init__(self):
....:         """Construct a Foo."""
sage: foo = Foo()
sage: from sage.misc.sageinspect import sage_getdoc
sage: sage_getdoc(foo)              # class docstring
'Construct a Foo.\n'
sage: sage_getdoc(foo.__init__)     # constructor docstring
'Construct a Foo.\n'

Latex 排版

在Sage的文档中, Latex 代码是允许的,并标有 backticks

`x^2 + y^2 = 1 ‘收益率’ x^2 + y^2 = 1

Backslashes: 对于包含反斜杠的LaTeX命令,要么使用双反斜杠,要么以 r""" 而不是 """ **

def cos(x):
    """
    Return `\\cos(x)`.
    """

def sin(x):
    r"""
    Return `\sin(x)`.
    """

我们强烈建议使用后者。

MATH block: 这类似于LaTeX语法 \[<math expression>\] (或 $$<math expression>$$ )。例如:

.. MATH::

    \sum_{i=1}^{\infty} (a_1 a_2 \cdots a_i)^{1/i}
    \leq
    e \sum_{i=1}^{\infty} a_i
\[\sum_{i=1}^{\infty} (a_1 a_2 \cdots a_i)^{1/i} \leq e \sum_{i=1}^{\infty} a_i\]

这个 aligned 环境的工作原理与在LaTeX中相同:

.. MATH::

    \begin{aligned}
     f(x) & = x^2 - 1 \\
     g(x) & = x^x - f(x - 2)
    \end{aligned}
\[\begin{split}\begin{aligned} f(x) & = x^2 - 1 \\ g(x) & = x^x - f(x - 2) \end{aligned}\end{split}\]

在构建PDF文档时,所有内容都被转换为LaTeX,并且每个数学块都自动包装在数学环境中--尤其是,它被转换为 \begin{gather} block \end{gather} 。因此,如果您想要使用LaTeX环境(如 align ),在普通 Latex 中不会这样包装,您必须添加一个 :nowrap: 标志设置为数学模式。另请参阅 Sphinx's documentation for math blocks 。:

.. MATH::
   :nowrap:

   \begin{align}
      1+...+n &= n(n+1)/2\\
      &= O(n^2)\\
   \end{align}
\begin{align} 1+...+n &= n(n+1)/2\\ &= O(n^2)\\ \end{align}

Readability balance: 在交互式控制台中,文档中包含的LaTeX公式由其LaTeX代码表示(去掉反斜杠)。在这种情况下 \\frac{a}{b} 可读性不如 a/ba b^{-1} (一些用户可能甚至不知道LaTeX代码)。尽你所能让每个人都感到愉快。

Commons rings (Bold{Z},Bold{N},...): The Sage LaTeX style is to typeset standard rings and fields using the locally-defined macro \\Bold (e.g. \\Bold{Z} gives Bold{Z}).

Shortcuts are available which preserve readability, e.g. \\ZZ (ZZ), \\RR (RR), \\CC (CC), and \\QQ (QQ). They appear as LaTeX-formatted \\Bold{Z} in the html manual, and as Z in the interactive help. Other examples: \\GF{q} (GF{q}) and \\Zmod{p} (Zmod{p}).

请参阅该文件 SAGE_ROOT/src/sage/misc/latex_macros.py 获取完整列表以及有关如何添加更多宏的详细信息。

编写可测试的示例

Sage文档中的示例具有双重用途:

  • 他们提供了 illustrations 用户对代码的使用情况

  • 他们是 tests 在每次发布之前都会进行检查,帮助我们避免新的错误。

添加到Sage的所有新文档测试应 pass all tests (见 运行Sage‘s Doctest ),即运行 sage -t your_file.py 不应给出任何错误消息。下面是关于应该如何编写文档测试的说明。

What doctests should test:

  • Interesting examples 该函数可以做些什么。这将是对迷路的用户最有帮助的。这也是检查著名定理的机会(以防万一):

    sage: is_prime(6) # 6 is not prime
    False
    sage: 2 * 3 # and here is a proof
    6
    
  • meaningful combinations 输入参数的。例如,一个函数可以接受 algorithm="B" 参数,并且文档测试应该同时涉及到 algorithm="A"algorithm="B"

  • Corner cases: 代码应该能够处理0输入、空集、空矩阵或空函数。所有角落的箱子都应该检查,因为无论现在还是将来,它们都最有可能被打破。这可能属于测试块(请参见 函数的文档字符串:Content )。

  • Systematic tests 所有小规模的输入或测试 random 实例,如果可能的话。

    备注

    请注意 TestSuites 是在特定情况下自动生成其中一些测试的方法。看见 SAGE_ROOT/src/sage/misc/sage_unittest.py

The syntax:

  • Environment: 如果您在Sage的交互控制台中复制/粘贴文档测试,它们应该可以工作。例如,函数 AA() 在文件中 SAGE_ROOT/src/sage/algebras/steenrod/steenrod_algebra.py 包括一个包含以下内容的示例块:

    sage: from sage.algebras.steenrod.steenrod_algebra import AA as A
    sage: A()
    mod 2 Steenrod algebra, milnor basis
    

    Sage并不知道这个功能 AA() 默认情况下,因此需要在测试之前将其导入。因此,本例中的第一行。

    同一文档字符串中的所有块都是链接的:文档测试中设置的变量将其其余文档测试的值保留在同一文档字符串中。为不同的值使用不同的变量名是一种很好的做法,因为这会让读者更容易理解示例中的数据流。(它还使Sage doctester中的数据流分析更加精确。)特别是,当不相关的示例出现在同一个文档字符串中时,不要对两个示例使用相同的变量名。

  • Preparsing: 就像在Sage的控制台中一样, 4/3 退货 4/3 而不是 1.3333333333333333 就像在 Python 里一样。测试在标准的SageShell环境中对输入进行充分的Sage准备,如中所述 Sage准备

  • Writing files: 如果测试输出到文件,则该文件应该是临时文件。使用 tmp_filename() 获取临时文件名,或者 tmp_dir() 以获取临时目录。下面是一个例子 SAGE_ROOT/src/sage/plot/graphics.py ):

    sage: plot(x^2 - 5, (x, 0, 5), ymin=0).save(tmp_filename(ext='.png'))
    
  • Multiline doctests: 您可以使用行接续符编写跨越多行的测试 ....: **

    sage: for n in srange(1,10):
    ....:     if n.is_prime():
    ....:         print(n)
    2
    3
    5
    7
    
  • Wrap long doctest lines: 请注意,示例块中的所有文档测试都被格式化为我们的HTML和PDF参考手册的一部分。我们的Html手册使用由 Furo theme 。即使将浏览器窗口展开以利用桌面宽屏幕的全部宽度,样式也不允许代码框任意变宽。

    最好在可能的情况下换行,这样读者就不需要水平滚动(来回滚动)来学习一个例子了。

    • 尽量在第80到88列周围换行,并且尽量不超过源文件中的第95列。(列号从源文件的左边距开始;无论文档字符串嵌套多深,这些规则都有效,因为格式化的输出也将嵌套。)

    • 如果必须在尚未嵌套在括号中的位置中断表达式,请将其括在括号中::

      sage: (len(list(Permutations(['a', 'b', 'c', 'd', 'e', 'f', 'g'])))
      ....:    == len(list(Permutations(7))))
      True
      
    • 如果您唯一的示例中的输出非常宽,并且不能合理地重新格式化以适应(例如,大型符号矩阵或具有多位数的数字),请考虑首先显示一个较小的示例。

    • 不需要包裹很长时间 import 发言。通常, import 语句并不是文档测试中有趣的部分。用户只需要能够将它们复制粘贴到Sage会话或源文件::

      sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict, MPolynomialRing_polydict_domain  # this is fine
      
    • 对长输出进行换行和缩进,以最大限度地提高源代码和HTML输出的可读性。但不要对字符串进行换行::

      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'
      

      此外,如果doctest输出中没有可以换行的空格,请不要添加这样的空格。不要换行::

      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标记,例如 # needs sage.modules (见 影响文档测试的特殊标记 )应在第88栏对齐。从一致的对齐中清理线条有助于减少视觉混乱。此外,在最大窗口宽度下,只有单词 # needs 将在没有水平滚动的情况下在HTML输出中可见,在呈现信息和减少视觉混乱之间取得了深思熟虑的平衡。(当然,能看到多少内容可能取决于浏览器。)在视觉密集的文档测试中,您可以尝试塑造视觉空间,以将测试命令与注释分开。

    • Doctest标签,如 # optional - pynormaliz 另一方面,这使得doctest的条件是是否存在可选的包,应该对齐,以便它们不必水平滚动就可以看到。这个 doctest fixer 在第48、56、64列使用制表位...这些标签。

  • Split long lines: 您可能想要用反斜杠分隔长代码行。注意:此语法是非标准的,将来可能会删除:

    sage: n = 123456789123456789123456789\
    ....:     123456789123456789123456789
    sage: n.is_prime()
    False
    
  • Doctests flags: 可以使用标志来更改文档测试的行为:请参见 影响文档测试的特殊标记

影响文档测试的特殊标记

示例代码中过于复杂的输出可以用省略号标记来缩短 ... **

sage: [ZZ(n).ordinal_str() for n in range(25)]
['0th',
 '1st',
 '2nd',
 '3rd',
 '4th',
 '5th',
 ...
 '21st',
 '22nd',
 '23rd',
 '24th']
sage: ZZ('sage')
Traceback (most recent call last):
...
TypeError: unable to convert 'sage' to an integer

有关省略号标记的正确用法,请参见 :python:`Python's documentation <library/doctest.html#doctest.ELLIPSIS>`

您可以在示例代码中添加许多神奇的注释,以更改Sage doctest框架验证输出的方式。以下是一份全面的名单:

  • random: 该行将被执行,但其输出不会与文档字符串中的输出进行检查::

    sage: c = CombinatorialObject([1,2,3])
    sage: hash(c)  # random
    1335416675971793195
    sage: hash(c)  # random
    This doctest passes too, as the output is not checked
    

    任何状态的伪随机数生成器(PRNG)都有望通过Doctest。在可能的情况下,避免这个问题,例如:不是在文档测试中检查散列值,而是可以说明成功地将其用作字典中的关键字。

    人们还可以避免 random -通过检查基本属性来标记::

    sage: QQ.random_element().parent() is QQ
    True
    sage: QQ.random_element() in QQ
    True
    sage: a = QQ.random_element()
    sage: b = QQ._random_nonzero_element()
    sage: c = QQ._random_nonzero_element()
    sage: (a/c) / (b/c) == a/b
    True
    

    可以使用循环检查分布::

    sage: found = {i: False for i in range(-2, 3)}
    sage: while not all(found.values()):
    ....:     found[ZZ.random_element(-2, 3)] = True
    

    这在数学上是正确的,因为它肯定会终止。但是,超时的可能性不为零。

  • long time: 只有在以下情况下才测试该线路 --long 给出了选项,例如 sage -t --long f.py

    对于运行时间超过一秒的文档测试,请使用它。任何示例花费的时间都不应超过30秒::

    sage: E = EllipticCurve([0, 0, 1, -1, 0])
    sage: E.regulator()        # long time (1 second)
    0.0511114082399688
    
  • toltolerance: 该行返回的数值仅验证为给定的公差。当输出因系统相关(浮点算术、数学库等)而受到数值噪声的影响时,它很有用。或非确定性算法。

    • 它的前缀可以是 abs[olute]rel[ative] 要指定是否测量 absoluterelative 错误(请参阅 :wikipedia:`Approximation_error` )。

    • 如果没有 abs/rel 则错误被认为是 absolute 当期望值为 zero ,并且是 relativenonzero 价值观。

    sage: n(pi)  # abs tol 1e-9
    3.14159265358979
    sage: n(pi)  # rel tol 2
    6
    sage: n(pi)  # abs tol 1.41593
    2
    sage: K.<zeta8> = CyclotomicField(8)
    sage: N(zeta8)  # absolute tolerance 1e-10
    0.7071067812 + 0.7071067812*I
    

    Multiple numerical values: 复数、矩阵或多项式的表示通常涉及几个数值。如果带有公差的文档测试包含多个数字,则分别检查每个数字::

    sage: print("The sum of 1 and 1 equals 5")  # abs tol 1
    The sum of 2 and 2 equals 4
    sage: e^(i*pi/4).n()  # rel tol 1e-1
    0.7 + 0.7*I
    sage: ((x+1.001)^4).expand()  # rel tol 2
    x^4 + 4*x^3 + 6*x^2 + 4*x + 1
    sage: M = matrix.identity(3) + random_matrix(RR,3,3)/10^3
    sage: M^2 # abs tol 1e-2
    [1 0 0]
    [0 1 0]
    [0 0 1]
    

    文档测试框架在错误计算中涉及的值由正则表达式定义 float_regex 在……里面 sage.doctest.parsing

  • not implementednot tested: 这条线路从未经过测试。

    将其用于仅用作文档的非常长的文档测试。它还可以用来记录最终将实施的内容:

    sage: factor(x*y - x*z)    # not implemented
    

    用户还可以立即清楚地看到,所指示的示例当前不起作用。

    备注

    跳过文件/目录的所有文档测试

    • file: 如果文件的前10行中有一行以以下任一行开头 r""" nodoctest (或 """ nodoctest# nodoctest% nodoctest.. nodoctest ,或其中任何一个具有不同的间距),则将跳过该文件。

    • directory: 如果目录包含文件 nodoctest.py ,则将跳过该整个目录。

    这两种方法都不适用于显式作为命令行参数给出的文件或目录:这些文件或目录总是要经过测试。

  • optional/needs: 带有标记的行 optional - FEATUREneeds FEATURE 不会进行测试,除非 --optional=KEYWORD 标志被传递到 sage -t (见 运行可选的文档测试 )。其主要应用包括:

    • optional packages: 当某行需要安装可选的软件包时(例如 sloane_database 包)::

      sage: SloaneEncyclopedia[60843]    # optional - sloane_database
      
    • internet: 对于需要互联网连接的线路:

      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.
      
    • known bugs: 对于描述已知错误的行,您可以使用 # optional - bug ,尽管 # known bug 是首选的。

      The following should yield 4.  See :issue:`2`. ::
      
          sage: 2+2  # optional - bug
          5
          sage: 2+2  # known bug
          5
      
    • modularization: 要启用 separate testing of the distribution packages 在模块化的Sage库中,可以标记依赖于其他发行包提供的功能的文档测试 # needs FEATURE 。例如:

      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?
      

    备注

    • 之后的任何词语 # optional# needs 被解释为由空格分隔的包(Spkg)名称或其他功能标签的列表。

    • 除下划线以外的任何标点符号 (_ )和句号 (. ),即,在第一个单词结束包裹列表之后,逗号、连字符、分号、...。单词之间的连字符或冒号 optional 和第一个包名是允许的。因此,你不应该写 # optional - depends on package CHomP 但简单地说 # optional - CHomP

    • 可选标记不区分大小写,因此您还可以编写 # optional - chOMP

    如果 # optional# needs 被放置在紧靠 sage: 提示时,它是块范围的标记,该标记将应用于所有doctest行,直到遇到空行。

    这些标记也可以应用于整个文件。如果文件的前10行中有一行以以下任一行开头 r""" sage.doctest: optional - FEATURE# sage.doctest: needs FEATURE ,或 .. sage.doctest: optional - FEATURE (在 .rst 文件)等,则这适用于该文件中的所有文档测试。

    跳过作为命令行参数显式给出的文件时,将显示警告。

    备注

    如果将这样的行添加到文件中,强烈建议您在模块级别的文档中添加注释,说明除非满足适当的条件,否则将跳过此文件中的doctest。

  • indirect doctest: 在函数的文档字符串中 A(...) ,一条线路在呼唤 A 其中的名字 A 没有出现应该有这面旗帜。这防止了 sage --coverage <file> 将文档字符串报告为“没有测试它应该测试的内容”。

    在测试特殊功能时使用它 __repr____add__ 等等。当您通过调用 B 它在内部调用 A

    This is the docstring of an ``__add__`` method. The following
    example tests it, but ``__add__`` is not written anywhere::
    
        sage: 1+1 # indirect doctest
        2
    
  • 32-bit64-bit: 适用于在32位或64位计算机上表现不同的测试。请注意,此特定标志将应用于 output 行,而不是输入行::

    sage: hash(2^31 + 2^13)
    8193                      # 32-bit
    2147491840                # 64-bit
    

每种编码样式 (Python代码样式 ),魔术注释应至少用2个空格隔开。

对于多行文档测试,注释应出现在第一个 physical line 文档测试(带有提示符的行 sage: ),不在继续行上(带有提示符的行 ....: ):

sage: print(ZZ.random_element())        # random
42
sage: for _ in range(3):                # random
....:     print(QQ.random_element())
1
1/77
-1/2

vbl.使用 search_src 从SAGE提示符(或 grep ),人们可以很容易地找到上述关键字。在.的情况下 todo: not implemented ,人们可以使用这样的搜索结果来指导Sage的进一步开发。

运行自动文档测试

本节介绍Sage对以下类型的测试文件进行的自动化测试: .py.pyx.sage.rst 。简而言之,使用 sage -t <file> 要测试中的示例 <file> 完全按照声称的方式行事。有关更多详细信息,请参阅以下小节。另请参阅 文档字符串 有关如何在文档字符串中包含示例以及应遵循哪些约定的讨论。这一章 运行Sage‘s Doctest 包含有关对Sage库中的模块进行文档测试的教程。

测试.py、.pyx和.sage文件

sage -t <filename.py> 测试中的所有代码示例 filename.py 。类似的评论也适用于 .sage.pyx 文件:

$ sage -t [--verbose] [--optional]  [files and directories ... ]

Sage doctest框架基于标准的Python doctest模块,但具有许多附加功能(如并行测试、超时、可选测试)。Sage博士测试员认识到 sage: 提示以及 >>> 提示。它还准备文档测试,就像在交互式Sage会议中一样。

如果文件中的代码在输入时将运行,则文件通过测试 sage: 提示,不需要额外的导入。因此,可以保证用户能够准确地从您为文档编写的示例中复制代码,并使它们正常工作。

有关详细信息,请参阅 运行Sage‘s Doctest

测试REST文档

sage -t <filename.rst> 在REST文档中的逐字环境中测试这些示例。

当然,在REST文件中,人们经常在不同的逐字环境之间插入说明性文本。若要逐字链接环境,请使用 .. link 评论。例如:

EXAMPLES::

        sage: a = 1


Next we add 1 to ``a``.

.. link::

        sage: 1 + a
        2

如果您想要将所有逐字环境链接在一起,可以将 .. linkall 文件中的任何位置,单独在一行上。(为清楚起见,最好将其放在文件顶部附近。)然后 sage -t 将会表现得好像有一个 .. link 在每个逐字记录的环境之前。档案 SAGE_ROOT/src/doc/en/tutorial/interfaces.rst 包含一个 .. linkall 指令,例如。

您也可以将 .. skip 在逐字测试环境之前,在测试文件时跳过该示例。它放在与 .. link 在上一个示例中。

请参阅中的文件 SAGE_ROOT/src/doc/en/tutorial/ 查看如何在Sage的REST文档中包含自动化测试的许多示例。

关于空格的通用编码风格

使用空格而不是制表符进行缩进。唯一的例外是生成文件,它的制表符具有与空格不同的语法含义。

请勿添加尾随空格。

Sage使用以下文件为Emacs提供了编辑器配置 .dir-locals.el ,使用空格而不是制表符。关于尾随空格,请参阅https://www.emacswiki.org/emacs/DeletingWhitespace了解各种解决方案。

如果您使用其他编辑器,我们建议对其进行配置,使您不向文件中添加选项卡。看见 与Sage一起使用的文本编辑器和IDE

全球期权

可以在Sage中使用以下命令定义类的全局选项 GlobalOptions

杂事小事

有些决定是武断的,但共同的惯例让生活变得更容易。

  • 标识符中的非ASCII名称:

    • 翻译 äöaeoe ,就像 moebius_function 对于Möbius函数。

    • 翻译 áa ,就像 lovasz_number 对于Lovász号。

  • 常见函数关键字参数:

    这是许多函数和方法采用的一些关键字参数的列表。为了保持一致性,您应该使用下面列表中的关键字,其含义如下所示。请勿使用含义相同的不同关键字(例如,请勿使用 method ;使用 algorithm 而是)。

    • algorithm 、字符串或 None :在各种实现或算法之间进行选择。使用 None 默认情况下,选择合理的默认设置,这可能取决于安装的可选程序包。

    • certificate ,一个布尔值, False 默认情况下:函数是否应与结果一起返回某种证书。使用 certificate=True 返回值应为一对 (r, c) 哪里 r 是将会用 certificate=Falsec 是证书还是 None 如果没有有意义的证书。

    • proof ,一个布尔值, True 作为默认设置:如果 True ,需要经过数学验证的计算。如果 False 可以使用概率算法或依赖于未经证实的假设的算法,例如RH。

    • check 布尔值:执行一些额外的检查以验证输入参数。这不应影响代码的功能:如果代码使用 check=True ,它还应该与 check=False

    • coerce ,布尔值:将输入参数转换为合适的父参数。这通常用在构造函数中。可以使用以下命令调用方法 coerce=False 以跳过一些检查,以确定父进程是否正确。

    • inplace ,布尔值:是就地修改对象还是返回副本。