Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
sagemathgh-37654: Developer guide: Improve discussion of backport packages
    
<!-- ^ Please provide a concise and informative title. -->
<!-- ^ Don't put issue numbers in the title, do this in the PR
description below. -->
<!-- ^ For example, instead of "Fixes sagemath#12345" use "Introduce new method
to calculate 1 + 2". -->
<!-- v Describe your changes below in detail. -->
<!-- v Why is this change required? What problem does it solve? -->
<!-- v If this PR resolves an open issue, please link to it here. For
example, "Fixes sagemath#12345". -->

- sagemath#35203 added these packages as unconditional dependencies
- prompted by a sporadic use of typing_extensions in the Sage library
(see sagemath#34831)
- motivated further by the demand to immediately drop support for Python
3.8 so that newer typing features can be used in the Sage library
(sagemath#35404)
- sagemath#36776 reduced the packages to
conditional dependencies

Here we improve the documentation in the section "Language standard" of
the developer's guide so that it aligns with how the conditional
dependencies are declared.

Based on changes split out from sagemath#37399.

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->

- [ ] The title is concise and informative.
- [ ] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on. For example,
-->
<!-- - sagemath#12345: short description why this is a dependency -->
<!-- - sagemath#34567: ... -->
    
URL: sagemath#37654
Reported by: Matthias Köppe
Reviewer(s): Kwankyu Lee, Matthias Köppe
  • Loading branch information
Release Manager committed Apr 20, 2024
2 parents ceaead0 + 7779ec5 commit 86f18c1
Showing 1 changed file with 62 additions and 41 deletions.
103 changes: 62 additions & 41 deletions src/doc/en/developer/coding_in_python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -61,29 +83,29 @@ 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.


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
Expand All @@ -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.


Expand All @@ -111,18 +133,18 @@ 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
typeset correctly within math mode. Do not include opening and
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
Expand All @@ -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.

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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`:

Expand All @@ -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:

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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:

Expand All @@ -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
Expand Down

0 comments on commit 86f18c1

Please sign in to comment.