diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index 9a325f01e52..7a2646b6891 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -14,9 +14,9 @@ Python language standard Sage library code needs to be compatible with all versions of Python that Sage supports. The information regarding the supported versions -can be found in the files ``build/pkgs/python3/spkg-configure.m4`` -(for the Sage distribution), ``m4/pyproject_toml_metadata.m4`` (for -the Sage library and most other distribution packages in ``pkgs/``). +can be found in the files :sage_root:`build/pkgs/python3/spkg-configure.m4` +(for the Sage distribution) and :sage_root:`m4/pyproject_toml_metadata.m4` (for +the Sage library and most other distribution packages in :sage_root:`pkgs/`). Python 3.9 is the oldest supported version. Hence, all language and library features that are available in Python 3.9 can @@ -38,14 +38,36 @@ using one of two mechanisms: - Backport packages - `importlib_metadata <../reference/spkg/importlib_metadata>`_ - (to be used in place of ``importlib.metadata``), + (to be used in place of ``importlib.metadata`` when Python older + than 3.11 is in use if you need a newer feature), - `importlib_resources <../reference/spkg/importlib_resources>`_ - (to be used in place of ``importlib.resources``), + (to be used in place of ``importlib.resources`` when Python older than + 3.11 is in use if you need a newer feature), - `typing_extensions <../reference/spkg/typing_extensions>`_ - (to be used in place of ``typing``). + (to be used in place of ``typing`` when Python older than + 3.11 is in use and any of the features introduced after Python + 3.9.0 are used). - The Sage library declares these packages as dependencies and ensures that - versions that provide features of Python 3.11 are available. + The Sage library declares these backport packages as conditional + dependencies for use with Python older than 3.11 and ensures that + versions of the packages that provide features of Python 3.11 + are available. + + The backport packages should not be imported unconditionally. + For example, on Linux distributions that only ship newer versions + of Python, the backport packages may not be available as + system packages. Hence, if there is a need to use the backport + packages, they should be imported like this: + + .. CODE-BLOCK:: python + + import sys + + if sys.version_info < (3, 11): + # Use backport package providing Python 3.11 features + from importlib_resources import files + else: + from importlib.resources import files Meta :issue:`29756` keeps track of newer Python features and serves as a starting point for discussions on how to make use of them in the @@ -61,7 +83,7 @@ into the structure of Sage. In particular, much of Sage is implemented in the object-oriented language Python, and there is a hierarchy of classes that organize code and functionality. For example, if you implement elements of a ring, your class should derive from -``sage.structure.element.RingElement``, rather than starting from +:class:`sage.structure.element.RingElement`, rather than starting from scratch. Try to figure out how your code should fit in with other Sage code, and design it accordingly. @@ -69,21 +91,21 @@ code, and design it accordingly. Special Sage functions ====================== -Functions with leading and trailing double underscores ``__XXX__`` are +Functions with leading and trailing double underscores :meth:`__XXX__` are all predefined by Python. Functions with leading and trailing single -underscores ``_XXX_`` are defined for Sage. Functions with a single +underscores :meth:`_XXX_` are defined for Sage. Functions with a single leading underscore are meant to be semi-private, and those with a double leading underscore are considered really private. Users can create functions with leading and trailing underscores. Just as Python has many standard special methods for objects, Sage -also has special methods. They are typically of the form ``_XXX_``. +also has special methods. They are typically of the form :meth:`_XXX_`. In a few cases, the trailing underscore is not included, but this will eventually be changed so that the trailing underscore is always included. This section describes these special methods. All objects in Sage should derive from the Cython extension class -``SageObject``: +:class:`SageObject`: .. CODE-BLOCK:: python @@ -101,7 +123,7 @@ or from some other already existing Sage class: class MyFavoriteAlgebra(Parent): ... -You should implement the ``_latex_`` and ``_repr_`` method for every +You should implement the :meth:`_latex_` and :meth:`_repr_` method for every object. The other methods depend on the nature of the object. @@ -111,7 +133,7 @@ LaTeX representation Every object ``x`` in Sage should support the command ``latex(x)``, so that any Sage object can be easily and accurately displayed via LaTeX. Here is how to make a class (and therefore its instances) -support the command ``latex``. +support the command :func:`latex`. #. Define a method ``_latex_(self)`` that returns a LaTeX representation of your object. It should be something that can be @@ -119,10 +141,10 @@ support the command ``latex``. closing $'s. #. Often objects are built up out of other Sage objects, and these - components should be typeset using the ``latex`` function. For + components should be typeset using :func:`latex` function. For example, if ``c`` is a coefficient of your object, and you want to typeset ``c`` using LaTeX, use ``latex(c)`` instead of - ``c._latex_()``, since ``c`` might not have a ``_latex_`` method, + ``c._latex_()``, since ``c`` might not have a :meth:`_latex_` method, and ``latex(c)`` knows how to deal with this. #. Do not forget to include a docstring and an example that @@ -131,7 +153,7 @@ support the command ``latex``. #. You can use any macros included in ``amsmath``, ``amssymb``, or ``amsfonts``, or the ones defined in :mod:`sage.misc.latex_macros`. -An example template for a ``_latex_`` method follows. Note that the +An example template for a :meth:`_latex_` method follows. Note that the ``.. skip`` line should not be included in your code; it is here to prevent doctests from running on this fake example. @@ -169,8 +191,8 @@ preferable because if you only define ``_repr_(self)`` and not they like. Also, some objects should print differently depending on the context. -Here is an example of the ``_latex_`` and ``_repr_`` functions for the -``Pi`` class. It is from the file +Here is an example of the :meth:`_latex_` and :meth:`_repr_` methods for the +:class:`Pi` class. It is from the file :sage_root:`src/sage/symbolic/constants.py`: .. CODE-BLOCK:: python @@ -197,8 +219,8 @@ Here is an example of the ``_latex_`` and ``_repr_`` functions for the Matrix or vector from object ============================ -Provide a ``_matrix_`` method for an object that can be coerced to a -matrix over a ring `R`. Then the Sage function ``matrix`` will work +Provide a :meth:`_matrix_` method for an object that can be coerced to a +matrix over a ring `R`. Then the Sage function :func:`matrix` will work for this object. The following is from @@ -218,8 +240,8 @@ The following is from def adjacency_matrix(self, sparse=None, boundary_first=False): ... -Similarly, provide a ``_vector_`` method for an object that can be -coerced to a vector over a ring `R`. Then the Sage function ``vector`` +Similarly, provide a :meth:`_vector_` method for an object that can be +coerced to a vector over a ring `R`. Then the Sage function :func:`vector` will work for this object. The following is from the file :sage_root:`src/sage/modules/free_module_element.pyx`: @@ -239,7 +261,7 @@ Sage preparsing To make Python even more usable interactively, there are a number of tweaks to the syntax made when you use Sage from the commandline or via the notebook (but not for Python code in the Sage -library). Technically, this is implemented by a ``preparse()`` +library). Technically, this is implemented by a :func:`preparse` function that rewrites the input string. Most notably, the following replacements are made: @@ -280,7 +302,7 @@ replacements are made: are very small. Large Sage integers are much more efficient than Python integers since they are implemented using the GMP C library. -Consult the file ``preparser.py`` for more details about Sage +Consult :mod:`sage.repl.preparse` for more details about Sage preparsing, more examples involving raw literals, etc. When a file ``foo.sage`` is loaded or attached in a Sage session, a @@ -313,7 +335,7 @@ The Sage coercion model The primary goal of coercion is to be able to transparently do arithmetic, comparisons, etc. between elements of distinct sets. For -example, when one writes `3 + 1/2`, one wants to perform arithmetic on +example, when one writes ``3 + 1/2``, one wants to perform arithmetic on the operands as rational numbers, despite the left term being an integer. This makes sense given the obvious and natural inclusion of the integers into the rational numbers. The goal of the coercion @@ -343,29 +365,28 @@ scope variable. .. {Put a tutorial on this here} Certain objects, e.g. matrices, may start out mutable and become -immutable later. See the file -:sage_root:`src/sage/structure/mutability.py`. +immutable later. See :mod:`sage.structure.mutability`. The __hash__ special method ============================ -Here is the definition of ``__hash__`` from the Python reference +Here is the definition of :meth:`__hash__` from the Python reference manual: - Called by built-in function ``hash()`` and for operations on members - of hashed collections including ``set``, ``frozenset``, and - ``dict``. ``__hash__()`` should return an integer. The only required + Called by built-in function :func:`hash` and for operations on members + of hashed collections including :class:`set`, :class:`frozenset`, and + :class:`dict`. :meth:`__hash__` should return an integer. The only required property is that objects which compare equal have the same hash value; it is advised to mix together the hash values of the components of the object that also play a part in comparison of objects by packing them into a tuple and hashing the tuple. - If a class does not define an ``__eq__()`` method it should not define - a ``__hash__()`` operation either; if it defines ``__eq__()`` but not - ``__hash__()``, its instances will not be usable as items in hashable + If a class does not define an :meth:`__eq__` method, it should not define + a :meth:`__hash__` operation either; if it defines :meth:`__eq__` but not + :meth:`__hash__`, its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an - ``__eq__()`` method, it should not implement ``__hash__()``, since the + :meth:`__eq__` method, it should not implement :meth:`__hash__`, since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket). @@ -418,7 +439,7 @@ Unfortunately, in Sage we simply cannot require because serious mathematics is simply too complicated for this rule. For example, the equalities ``z == Mod(z, 2)`` and -``z == Mod(z, 3)`` would force ``hash()`` to be constant on the +``z == Mod(z, 3)`` would force :func:`hash` to be constant on the integers. The only way we could "fix" this problem for good would be to abandon @@ -457,7 +478,7 @@ Please avoid catch-all code like this: more_code() If you do not have any exceptions explicitly listed (as a tuple), your -code will catch absolutely anything, including ``ctrl-C``, typos in +code will catch absolutely anything, including :kbd:`Ctrl` + :kbd:`C`, typos in the code, and alarms, and this will lead to confusion. Also, this might catch real errors which should be propagated to the user. @@ -514,7 +535,7 @@ to explore the resulting integers' number-theoretic properties such as prime factorization. Exceptions should be made when there are good reasons such as performance or compatibility with Python code, for instance in methods such as -``__hash__``, ``__len__``, and ``__int__``. +:meth:`__hash__`, :meth:`__len__`, and :meth:`__int__`. To return a Python integer ``i`` as a Sage integer, use: @@ -523,7 +544,7 @@ To return a Python integer ``i`` as a Sage integer, use: from sage.rings.integer import Integer return Integer(i) -To return a Sage integer ``i`` as a Python ineger, use: +To return a Sage integer ``i`` as a Python integer, use: .. CODE-BLOCK:: python