From 8ba3074288e807ec60f16c4081717e3e93b865ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Wed, 30 Jul 2025 14:11:54 +0200 Subject: [PATCH 1/9] 40501 --- build/pkgs/symengine/checksums.ini | 4 ++-- build/pkgs/symengine/package-version.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/symengine/checksums.ini b/build/pkgs/symengine/checksums.ini index 72907d5595e..35f51ec6115 100644 --- a/build/pkgs/symengine/checksums.ini +++ b/build/pkgs/symengine/checksums.ini @@ -1,4 +1,4 @@ tarball=symengine-VERSION.tar.gz -sha1=2dfee07108509963f3dbe3d9cad9de76d85e551f -sha256=f6972acd6a65354f6414e69460d2e175729470632bdac05919bc2f7f32e48cbd +sha1=e53aa2677bcad5a5dc075a94d4a4f9ef95b5fe07 +sha256=11c5f64e9eec998152437f288b8429ec001168277d55f3f5f1df78e3cf129707 upstream_url=https://github.com/symengine/symengine/releases/download/vVERSION/symengine-VERSION.tar.gz diff --git a/build/pkgs/symengine/package-version.txt b/build/pkgs/symengine/package-version.txt index a8839f70de0..a803cc227fe 100644 --- a/build/pkgs/symengine/package-version.txt +++ b/build/pkgs/symengine/package-version.txt @@ -1 +1 @@ -0.11.2 \ No newline at end of file +0.14.0 From e90e6ef21fc939f363aa0965c78d380569e21d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Wed, 30 Jul 2025 14:12:59 +0200 Subject: [PATCH 2/9] 40501 --- build/pkgs/qhull/patches/qhull_cmake.patch | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 build/pkgs/qhull/patches/qhull_cmake.patch diff --git a/build/pkgs/qhull/patches/qhull_cmake.patch b/build/pkgs/qhull/patches/qhull_cmake.patch new file mode 100644 index 00000000000..a3b5f070414 --- /dev/null +++ b/build/pkgs/qhull/patches/qhull_cmake.patch @@ -0,0 +1,22 @@ +*** src/CMakeLists.txt.orig Thu May 8 13:21:24 2025 +--- src/CMakeLists.txt Thu May 8 13:25:39 2025 +*************** +*** 67,74 **** + # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ + # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ + + project(qhull) +- cmake_minimum_required(VERSION 3.0) + + # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt + # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm +--- 67,75 ---- + # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ + # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ + ++ cmake_minimum_required(VERSION 4.0) ++ + project(qhull) + + # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt + # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm From 2c2f2bb6825b59ac57693807b084473a4db802d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Wed, 30 Jul 2025 19:49:19 +0200 Subject: [PATCH 3/9] cmake 3.25 --- build/pkgs/qhull/patches/qhull_cmake.patch | 2 +- conftest.py | 347 --------------------- 2 files changed, 1 insertion(+), 348 deletions(-) delete mode 100644 conftest.py diff --git a/build/pkgs/qhull/patches/qhull_cmake.patch b/build/pkgs/qhull/patches/qhull_cmake.patch index a3b5f070414..892c8ac2525 100644 --- a/build/pkgs/qhull/patches/qhull_cmake.patch +++ b/build/pkgs/qhull/patches/qhull_cmake.patch @@ -14,7 +14,7 @@ # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ -+ cmake_minimum_required(VERSION 4.0) ++ cmake_minimum_required(VERSION 3.25) + project(qhull) diff --git a/conftest.py b/conftest.py deleted file mode 100644 index 5307d7f6233..00000000000 --- a/conftest.py +++ /dev/null @@ -1,347 +0,0 @@ -# pyright: strict -"""Configuration and fixtures for pytest. - -This file configures pytest and provides some global fixtures. -See https://docs.pytest.org/en/latest/index.html for more details. -""" - -from __future__ import annotations - -import doctest -import inspect -import sys -import warnings -from pathlib import Path -from typing import Any, Iterable, Optional - -import pytest -from _pytest.doctest import ( - DoctestItem, - DoctestModule, - _get_continue_on_failure, - _get_runner, - _is_mocked, - _patch_unwrap_mock_aware, - get_optionflags, -) -from _pytest.pathlib import ImportMode, import_path - -from sage.doctest.forker import ( - init_sage, - showwarning_with_traceback, -) -from sage.doctest.parsing import SageDocTestParser, SageOutputChecker - - -class SageDoctestModule(DoctestModule): - """ - This is essentially a copy of `DoctestModule` from - https://github.com/pytest-dev/pytest/blob/main/src/_pytest/doctest.py. - The only change is that we use `SageDocTestParser` to extract the doctests - and `SageOutputChecker` to verify the output. - """ - - def collect(self) -> Iterable[DoctestItem]: - import doctest - - class MockAwareDocTestFinder(doctest.DocTestFinder): - """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug. - https://github.com/pytest-dev/pytest/issues/3456 - https://bugs.python.org/issue25532 - """ - - def __init__(self) -> None: - super().__init__(parser=SageDocTestParser(set(["sage"]))) - - def _find_lineno(self, obj, source_lines): - """Doctest code does not take into account `@property`, this - is a hackish way to fix it. https://bugs.python.org/issue17446 - Wrapped Doctests will need to be unwrapped so the correct - line number is returned. This will be reported upstream. #8796 - """ - if isinstance(obj, property): - obj = getattr(obj, "fget", obj) - - if hasattr(obj, "__wrapped__"): - # Get the main obj in case of it being wrapped - obj = inspect.unwrap(obj) - - # Type ignored because this is a private function. - return super()._find_lineno( # type:ignore[misc] - obj, - source_lines, - ) - - def _find( - self, tests, obj, name, module, source_lines, globs, seen - ) -> None: - if _is_mocked(obj): - return - with _patch_unwrap_mock_aware(): - # Type ignored because this is a private function. - super()._find( # type:ignore[misc] - tests, obj, name, module, source_lines, globs, seen - ) - - if self.path.name == "conftest.py": - module = self.config.pluginmanager._importconftest( - self.path, - self.config.getoption("importmode"), - rootpath=self.config.rootpath, - consider_namespace_packages=True, - ) - else: - try: - module = import_path( - self.path, - mode=ImportMode.importlib, - root=self.config.rootpath, - consider_namespace_packages=True, - ) - except ImportError as exception: - if self.config.getvalue("doctest_ignore_import_errors"): - pytest.skip("unable to import module %r" % self.path) - else: - if isinstance(exception, ModuleNotFoundError): - # Ignore some missing features/modules for now - # TODO: Remove this once all optional things are using Features - if exception.name in ( - "valgrind", - "rpy2", - "sage.libs.coxeter3.coxeter", - ): - pytest.skip( - f"unable to import module { self.path } due to missing feature { exception.name }" - ) - raise - # Uses internal doctest module parsing mechanism. - finder = MockAwareDocTestFinder() - optionflags = get_optionflags(self.config) - from sage.features import FeatureNotPresentError - - runner = _get_runner( - verbose=False, - optionflags=optionflags, - checker=SageOutputChecker(), - continue_on_failure=_get_continue_on_failure(self.config), - ) - try: - for test in finder.find(module, module.__name__): - if test.examples: # skip empty doctests - yield DoctestItem.from_parent( - self, name=test.name, runner=runner, dtest=test - ) - except FeatureNotPresentError as exception: - pytest.skip( - f"unable to import module { self.path } due to missing feature { exception.feature.name }" - ) - except ModuleNotFoundError as exception: - # TODO: Remove this once all optional things are using Features - pytest.skip( - f"unable to import module { self.path } due to missing module { exception.name }" - ) - - -class IgnoreCollector(pytest.Collector): - """ - Ignore a file. - """ - - def __init__(self, parent: pytest.Collector) -> None: - super().__init__("ignore", parent) - - def collect(self) -> Iterable[pytest.Item | pytest.Collector]: - return [] - - -def pytest_collect_file( - file_path: Path, parent: pytest.Collector -) -> pytest.Collector | None: - """ - This hook is called when collecting test files, and can be used to - modify the file or test selection logic by returning a list of - ``pytest.Item`` objects which the ``pytest`` command will directly - add to the list of test items. - - See `pytest documentation `_. - """ - if ( - file_path.parent.name == "combinat" - or file_path.parent.parent.name == "combinat" - ): - # Crashes CI for some reason - return IgnoreCollector.from_parent(parent) - if file_path.suffix == ".pyx": - # We don't allow pytests to be defined in Cython files. - # Normally, Cython files are filtered out already by pytest and we only - # hit this here if someone explicitly runs `pytest some_file.pyx`. - return IgnoreCollector.from_parent(parent) - elif file_path.suffix == ".py": - if parent.config.option.doctest: - if file_path.name == "__main__.py" or file_path.name == "setup.py": - # We don't allow tests to be defined in __main__.py/setup.py files (because their import will fail). - return IgnoreCollector.from_parent(parent) - if ( - ( - file_path.name == "postprocess.py" - and file_path.parent.name == "nbconvert" - ) - or ( - file_path.name == "giacpy-mkkeywords.py" - and file_path.parent.name == "autogen" - ) - or ( - file_path.name == "flint_autogen.py" - and file_path.parent.name == "autogen" - ) - ): - # This is an executable file. - return IgnoreCollector.from_parent(parent) - - if file_path.name == "conftest_inputtest.py": - # This is an input file for testing the doctest machinery (and contains broken doctests). - return IgnoreCollector.from_parent(parent) - - if ( - ( - file_path.name == "finite_dimensional_lie_algebras_with_basis.py" - and file_path.parent.name == "categories" - ) - or ( - file_path.name == "__init__.py" - and file_path.parent.name == "crypto" - ) - or (file_path.name == "__init__.py" and file_path.parent.name == "mq") - ): - # TODO: Fix these (import fails with "RuntimeError: dictionary changed size during iteration") - return IgnoreCollector.from_parent(parent) - - if ( - file_path.name in ("forker.py", "reporting.py") - ) and file_path.parent.name == "doctest": - # Fails with many errors due to different testing framework - return IgnoreCollector.from_parent(parent) - - if ( - ( - file_path.name == "arithgroup_generic.py" - and file_path.parent.name == "arithgroup" - ) - or ( - file_path.name == "pari.py" - and file_path.parent.name == "lfunctions" - ) - or ( - file_path.name == "permgroup_named.py" - and file_path.parent.name == "perm_gps" - ) - or ( - file_path.name == "finitely_generated.py" - and file_path.parent.name == "matrix_gps" - ) - or ( - file_path.name == "libgap_mixin.py" - and file_path.parent.name == "groups" - ) - or ( - file_path.name == "finitely_presented.py" - and file_path.parent.name == "groups" - ) - or ( - file_path.name == "classical_geometries.py" - and file_path.parent.name == "generators" - ) - ): - # Fails with "Fatal Python error" - return IgnoreCollector.from_parent(parent) - - return SageDoctestModule.from_parent(parent, path=file_path) - - -def pytest_addoption(parser): - # Add a command line option to run doctests - # (we don't use the built-in --doctest-modules option because then doctests are collected twice) - group = parser.getgroup("collect") - group.addoption( - "--doctest", - action="store_true", - default=False, - help="Run doctests in all .py modules", - dest="doctest", - ) - - -# Monkey patch exception printing to replace the full qualified name of the exception by its short name -# TODO: Remove this hack once migration to pytest is complete -import traceback - -old_format_exception_only = traceback.format_exception_only - - -def format_exception_only(etype: type, value: BaseException) -> list[str]: - formatted_exception = old_format_exception_only(etype, value) - exception_name = etype.__name__ - if etype.__module__: - exception_full_name = etype.__module__ + "." + etype.__qualname__ - else: - exception_full_name = etype.__qualname__ - - for i, line in enumerate(formatted_exception): - if line.startswith(exception_full_name): - formatted_exception[i] = line.replace( - exception_full_name, exception_name, 1 - ) - return formatted_exception - - -# Initialize Sage-specific doctest stuff -init_sage() - -# Monkey patch doctest to use our custom printer etc -old_run = doctest.DocTestRunner.run - - -def doctest_run( - self: doctest.DocTestRunner, - test: doctest.DocTest, - compileflags: Optional[int] = None, - out: Any = None, - clear_globs: bool = True, -) -> doctest.TestResults: - from sage.repl.rich_output import get_display_manager - from sage.repl.user_globals import set_globals - - traceback.format_exception_only = format_exception_only - - # Display warnings in doctests - warnings.showwarning = showwarning_with_traceback - setattr(sys, "__displayhook__", get_display_manager().displayhook) - - # Ensure that injecting globals works as expected in doctests - set_globals(test.globs) - return old_run(self, test, compileflags, out, clear_globs) - - -doctest.DocTestRunner.run = doctest_run - - -@pytest.fixture(autouse=True, scope="session") -def add_imports(doctest_namespace: dict[str, Any]): - """ - Add global imports for doctests. - - See `pytest documentation `. - """ - # Inject sage.all into each doctest - import sage.repl.ipython_kernel.all_jupyter - - dict_all = sage.repl.ipython_kernel.all_jupyter.__dict__ - - # Remove '__package__' item from the globals since it is not - # always in the globals in an actual Sage session. - dict_all.pop("__package__", None) - - sage_namespace = dict(dict_all) - sage_namespace["__name__"] = "__main__" - - doctest_namespace.update(**sage_namespace) From 746cd6ba6db6d842d2bc928d3e0c52d57739715c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Wed, 30 Jul 2025 22:09:51 +0200 Subject: [PATCH 4/9] cmake 3.25...4.0.3 --- build/pkgs/qhull/patches/qhull_cmake.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/qhull/patches/qhull_cmake.patch b/build/pkgs/qhull/patches/qhull_cmake.patch index 892c8ac2525..fd98a127f40 100644 --- a/build/pkgs/qhull/patches/qhull_cmake.patch +++ b/build/pkgs/qhull/patches/qhull_cmake.patch @@ -14,7 +14,7 @@ # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ -+ cmake_minimum_required(VERSION 3.25) ++ cmake_minimum_required(VERSION 3.25...4.0.3) + project(qhull) From 496831b4bd31c7ec396829c922baa5da26d3874e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Thu, 31 Jul 2025 20:10:46 +0200 Subject: [PATCH 5/9] by Artal --- build/pkgs/gap_packages/spkg-install.in | 10 +++++++++- src/doc/en/prep/Logging-On.rst | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build/pkgs/gap_packages/spkg-install.in b/build/pkgs/gap_packages/spkg-install.in index c67a1176a69..314a784c5c7 100644 --- a/build/pkgs/gap_packages/spkg-install.in +++ b/build/pkgs/gap_packages/spkg-install.in @@ -92,7 +92,7 @@ install_compiled_pkg() # # These packages have an old ./configure that take the GAP_ROOT as a positional # argument -for pkg in cohomolo crypting grape guava orb datastructures +for pkg in cohomolo crypting grape orb datastructures do echo "Building GAP package $pkg" CFLAGS="$CFLAGS -Wno-implicit-function-declaration" @@ -104,6 +104,14 @@ do cd "$PKG_SRC_DIR" done +echo "Building GAP package guava" +export CFLAGS="-std=gnu17 $CFLAGS -Wno-implicit-function-declaration" +cd "$PKG_SRC_DIR/guava" +./configure "$GAP_ROOT" +sdh_make +install_compiled_pkg "guava" +cd "$PKG_SRC_DIR" + # These packages have a new-style autoconf ./configure # that takes --with-gaproot diff --git a/src/doc/en/prep/Logging-On.rst b/src/doc/en/prep/Logging-On.rst index 2181e22011b..e434cc3bcd5 100644 --- a/src/doc/en/prep/Logging-On.rst +++ b/src/doc/en/prep/Logging-On.rst @@ -54,7 +54,7 @@ the third option to "export" them will not make sense. The legacy SageNB has been retired in Sage 9.1. Please use the Jupyter notebook. Old SageNB worksheets can be converted to Jupyter notebooks -using the `sage --notebook=export`_ command or to RST +using the `sage --notebook=export` command or to RST using the `sage-sws2rst `_ package. Jupyter will bring you to a screen From 96245a0e1851e3ff4e1d614555ee22bbff11235f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Fri, 1 Aug 2025 02:53:48 +0200 Subject: [PATCH 6/9] conftest.py --- conftest.py | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 conftest.py diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000000..5307d7f6233 --- /dev/null +++ b/conftest.py @@ -0,0 +1,347 @@ +# pyright: strict +"""Configuration and fixtures for pytest. + +This file configures pytest and provides some global fixtures. +See https://docs.pytest.org/en/latest/index.html for more details. +""" + +from __future__ import annotations + +import doctest +import inspect +import sys +import warnings +from pathlib import Path +from typing import Any, Iterable, Optional + +import pytest +from _pytest.doctest import ( + DoctestItem, + DoctestModule, + _get_continue_on_failure, + _get_runner, + _is_mocked, + _patch_unwrap_mock_aware, + get_optionflags, +) +from _pytest.pathlib import ImportMode, import_path + +from sage.doctest.forker import ( + init_sage, + showwarning_with_traceback, +) +from sage.doctest.parsing import SageDocTestParser, SageOutputChecker + + +class SageDoctestModule(DoctestModule): + """ + This is essentially a copy of `DoctestModule` from + https://github.com/pytest-dev/pytest/blob/main/src/_pytest/doctest.py. + The only change is that we use `SageDocTestParser` to extract the doctests + and `SageOutputChecker` to verify the output. + """ + + def collect(self) -> Iterable[DoctestItem]: + import doctest + + class MockAwareDocTestFinder(doctest.DocTestFinder): + """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug. + https://github.com/pytest-dev/pytest/issues/3456 + https://bugs.python.org/issue25532 + """ + + def __init__(self) -> None: + super().__init__(parser=SageDocTestParser(set(["sage"]))) + + def _find_lineno(self, obj, source_lines): + """Doctest code does not take into account `@property`, this + is a hackish way to fix it. https://bugs.python.org/issue17446 + Wrapped Doctests will need to be unwrapped so the correct + line number is returned. This will be reported upstream. #8796 + """ + if isinstance(obj, property): + obj = getattr(obj, "fget", obj) + + if hasattr(obj, "__wrapped__"): + # Get the main obj in case of it being wrapped + obj = inspect.unwrap(obj) + + # Type ignored because this is a private function. + return super()._find_lineno( # type:ignore[misc] + obj, + source_lines, + ) + + def _find( + self, tests, obj, name, module, source_lines, globs, seen + ) -> None: + if _is_mocked(obj): + return + with _patch_unwrap_mock_aware(): + # Type ignored because this is a private function. + super()._find( # type:ignore[misc] + tests, obj, name, module, source_lines, globs, seen + ) + + if self.path.name == "conftest.py": + module = self.config.pluginmanager._importconftest( + self.path, + self.config.getoption("importmode"), + rootpath=self.config.rootpath, + consider_namespace_packages=True, + ) + else: + try: + module = import_path( + self.path, + mode=ImportMode.importlib, + root=self.config.rootpath, + consider_namespace_packages=True, + ) + except ImportError as exception: + if self.config.getvalue("doctest_ignore_import_errors"): + pytest.skip("unable to import module %r" % self.path) + else: + if isinstance(exception, ModuleNotFoundError): + # Ignore some missing features/modules for now + # TODO: Remove this once all optional things are using Features + if exception.name in ( + "valgrind", + "rpy2", + "sage.libs.coxeter3.coxeter", + ): + pytest.skip( + f"unable to import module { self.path } due to missing feature { exception.name }" + ) + raise + # Uses internal doctest module parsing mechanism. + finder = MockAwareDocTestFinder() + optionflags = get_optionflags(self.config) + from sage.features import FeatureNotPresentError + + runner = _get_runner( + verbose=False, + optionflags=optionflags, + checker=SageOutputChecker(), + continue_on_failure=_get_continue_on_failure(self.config), + ) + try: + for test in finder.find(module, module.__name__): + if test.examples: # skip empty doctests + yield DoctestItem.from_parent( + self, name=test.name, runner=runner, dtest=test + ) + except FeatureNotPresentError as exception: + pytest.skip( + f"unable to import module { self.path } due to missing feature { exception.feature.name }" + ) + except ModuleNotFoundError as exception: + # TODO: Remove this once all optional things are using Features + pytest.skip( + f"unable to import module { self.path } due to missing module { exception.name }" + ) + + +class IgnoreCollector(pytest.Collector): + """ + Ignore a file. + """ + + def __init__(self, parent: pytest.Collector) -> None: + super().__init__("ignore", parent) + + def collect(self) -> Iterable[pytest.Item | pytest.Collector]: + return [] + + +def pytest_collect_file( + file_path: Path, parent: pytest.Collector +) -> pytest.Collector | None: + """ + This hook is called when collecting test files, and can be used to + modify the file or test selection logic by returning a list of + ``pytest.Item`` objects which the ``pytest`` command will directly + add to the list of test items. + + See `pytest documentation `_. + """ + if ( + file_path.parent.name == "combinat" + or file_path.parent.parent.name == "combinat" + ): + # Crashes CI for some reason + return IgnoreCollector.from_parent(parent) + if file_path.suffix == ".pyx": + # We don't allow pytests to be defined in Cython files. + # Normally, Cython files are filtered out already by pytest and we only + # hit this here if someone explicitly runs `pytest some_file.pyx`. + return IgnoreCollector.from_parent(parent) + elif file_path.suffix == ".py": + if parent.config.option.doctest: + if file_path.name == "__main__.py" or file_path.name == "setup.py": + # We don't allow tests to be defined in __main__.py/setup.py files (because their import will fail). + return IgnoreCollector.from_parent(parent) + if ( + ( + file_path.name == "postprocess.py" + and file_path.parent.name == "nbconvert" + ) + or ( + file_path.name == "giacpy-mkkeywords.py" + and file_path.parent.name == "autogen" + ) + or ( + file_path.name == "flint_autogen.py" + and file_path.parent.name == "autogen" + ) + ): + # This is an executable file. + return IgnoreCollector.from_parent(parent) + + if file_path.name == "conftest_inputtest.py": + # This is an input file for testing the doctest machinery (and contains broken doctests). + return IgnoreCollector.from_parent(parent) + + if ( + ( + file_path.name == "finite_dimensional_lie_algebras_with_basis.py" + and file_path.parent.name == "categories" + ) + or ( + file_path.name == "__init__.py" + and file_path.parent.name == "crypto" + ) + or (file_path.name == "__init__.py" and file_path.parent.name == "mq") + ): + # TODO: Fix these (import fails with "RuntimeError: dictionary changed size during iteration") + return IgnoreCollector.from_parent(parent) + + if ( + file_path.name in ("forker.py", "reporting.py") + ) and file_path.parent.name == "doctest": + # Fails with many errors due to different testing framework + return IgnoreCollector.from_parent(parent) + + if ( + ( + file_path.name == "arithgroup_generic.py" + and file_path.parent.name == "arithgroup" + ) + or ( + file_path.name == "pari.py" + and file_path.parent.name == "lfunctions" + ) + or ( + file_path.name == "permgroup_named.py" + and file_path.parent.name == "perm_gps" + ) + or ( + file_path.name == "finitely_generated.py" + and file_path.parent.name == "matrix_gps" + ) + or ( + file_path.name == "libgap_mixin.py" + and file_path.parent.name == "groups" + ) + or ( + file_path.name == "finitely_presented.py" + and file_path.parent.name == "groups" + ) + or ( + file_path.name == "classical_geometries.py" + and file_path.parent.name == "generators" + ) + ): + # Fails with "Fatal Python error" + return IgnoreCollector.from_parent(parent) + + return SageDoctestModule.from_parent(parent, path=file_path) + + +def pytest_addoption(parser): + # Add a command line option to run doctests + # (we don't use the built-in --doctest-modules option because then doctests are collected twice) + group = parser.getgroup("collect") + group.addoption( + "--doctest", + action="store_true", + default=False, + help="Run doctests in all .py modules", + dest="doctest", + ) + + +# Monkey patch exception printing to replace the full qualified name of the exception by its short name +# TODO: Remove this hack once migration to pytest is complete +import traceback + +old_format_exception_only = traceback.format_exception_only + + +def format_exception_only(etype: type, value: BaseException) -> list[str]: + formatted_exception = old_format_exception_only(etype, value) + exception_name = etype.__name__ + if etype.__module__: + exception_full_name = etype.__module__ + "." + etype.__qualname__ + else: + exception_full_name = etype.__qualname__ + + for i, line in enumerate(formatted_exception): + if line.startswith(exception_full_name): + formatted_exception[i] = line.replace( + exception_full_name, exception_name, 1 + ) + return formatted_exception + + +# Initialize Sage-specific doctest stuff +init_sage() + +# Monkey patch doctest to use our custom printer etc +old_run = doctest.DocTestRunner.run + + +def doctest_run( + self: doctest.DocTestRunner, + test: doctest.DocTest, + compileflags: Optional[int] = None, + out: Any = None, + clear_globs: bool = True, +) -> doctest.TestResults: + from sage.repl.rich_output import get_display_manager + from sage.repl.user_globals import set_globals + + traceback.format_exception_only = format_exception_only + + # Display warnings in doctests + warnings.showwarning = showwarning_with_traceback + setattr(sys, "__displayhook__", get_display_manager().displayhook) + + # Ensure that injecting globals works as expected in doctests + set_globals(test.globs) + return old_run(self, test, compileflags, out, clear_globs) + + +doctest.DocTestRunner.run = doctest_run + + +@pytest.fixture(autouse=True, scope="session") +def add_imports(doctest_namespace: dict[str, Any]): + """ + Add global imports for doctests. + + See `pytest documentation `. + """ + # Inject sage.all into each doctest + import sage.repl.ipython_kernel.all_jupyter + + dict_all = sage.repl.ipython_kernel.all_jupyter.__dict__ + + # Remove '__package__' item from the globals since it is not + # always in the globals in an actual Sage session. + dict_all.pop("__package__", None) + + sage_namespace = dict(dict_all) + sage_namespace["__name__"] = "__main__" + + doctest_namespace.update(**sage_namespace) From 8705d5701a782a5132e3779a827c5950a5737a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Sat, 2 Aug 2025 23:03:21 +0200 Subject: [PATCH 7/9] 40519 new --- CITATION.cff | 4 +- VERSION.txt | 2 +- build/bin/sage-print-system-package-command | 1 + build/pkgs/configure/checksums.ini | 4 +- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/gap_packages/spkg-install.in | 10 +- build/pkgs/ncurses/distros/debian.txt | 2 +- build/pkgs/polymake/checksums.ini | 5 +- build/pkgs/polymake/package-version.txt | 2 +- build/pkgs/qhull/patches/qhull_cmake.patch | 22 - build/pkgs/roman_numerals_py/SPKG.rst | 26 + build/pkgs/roman_numerals_py/checksums.ini | 4 + build/pkgs/roman_numerals_py/dependencies | 4 + build/pkgs/roman_numerals_py/distros/arch.txt | 1 + .../pkgs/roman_numerals_py/distros/conda.txt | 1 + .../pkgs/roman_numerals_py/distros/fedora.txt | 1 + .../roman_numerals_py/distros/freebsd.txt | 1 + .../pkgs/roman_numerals_py/distros/gentoo.txt | 1 + .../roman_numerals_py/distros/macports.txt | 1 + .../roman_numerals_py/distros/opensuse.txt | 1 + .../roman_numerals_py/package-version.txt | 1 + .../pkgs/roman_numerals_py/spkg-configure.m4 | 3 + build/pkgs/roman_numerals_py/type | 1 + .../version_requirements.txt | 1 + build/pkgs/sage_conf/version_requirements.txt | 2 +- .../sage_docbuild/version_requirements.txt | 2 +- .../pkgs/sage_setup/version_requirements.txt | 2 +- build/pkgs/sagelib/version_requirements.txt | 2 +- .../sagemath_bliss/version_requirements.txt | 2 +- .../version_requirements.txt | 2 +- .../version_requirements.txt | 2 +- .../version_requirements.txt | 2 +- .../sagemath_mcqd/version_requirements.txt | 2 +- .../sagemath_meataxe/version_requirements.txt | 2 +- .../sagemath_objects/version_requirements.txt | 2 +- .../sagemath_repl/version_requirements.txt | 2 +- .../sagemath_sirocco/version_requirements.txt | 2 +- .../sagemath_tdlib/version_requirements.txt | 2 +- build/pkgs/sphinx/checksums.ini | 4 +- build/pkgs/sphinx/dependencies | 2 +- build/pkgs/sphinx/package-version.txt | 2 +- build/pkgs/sphinx/version_requirements.txt | 2 +- build/pkgs/symengine/checksums.ini | 4 +- build/pkgs/symengine/package-version.txt | 2 +- build/pkgs/symmetrica/distros/debian.txt | 2 +- conftest.py | 4 - environment-3.11-linux-aarch64.yml | 80 +- environment-3.11-linux.yml | 82 +- environment-3.11-macos-x86_64.yml | 122 +- environment-3.11-macos.yml | 94 +- environment-3.11-win.yml | 86 +- environment-3.12-linux-aarch64.yml | 80 +- environment-3.12-linux.yml | 82 +- environment-3.12-macos-x86_64.yml | 122 +- environment-3.12-macos.yml | 94 +- environment-3.12-win.yml | 86 +- environment-3.13-win.yml | 86 +- meson.options | 9 + pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf/_sage_conf/_conf.py.in | 1 + pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sagemath-bliss/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-coxeter3/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-mcqd/VERSION.txt | 2 +- pkgs/sagemath-meataxe/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- pkgs/sagemath-sirocco/VERSION.txt | 2 +- pkgs/sagemath-tdlib/VERSION.txt | 2 +- pyproject.toml | 168 +-- src/VERSION.txt | 2 +- src/bin/math-readline | 6 +- src/bin/sage | 8 +- src/bin/sage-cachegrind | 2 +- src/bin/sage-cleaner | 13 +- src/bin/sage-eval | 5 +- src/bin/sage-fixdoctests | 2 +- src/bin/sage-ipython | 3 +- src/bin/sage-list-packages | 2 +- src/bin/sage-massif | 2 +- src/bin/sage-notebook | 13 +- src/bin/sage-omega | 2 +- src/bin/sage-preparse | 6 +- src/bin/sage-python | 2 - src/bin/sage-run | 9 +- src/bin/sage-run-cython | 6 +- src/bin/sage-runtests | 3 +- src/bin/sage-startuptime.py | 2 +- src/bin/sage-version.sh | 6 +- src/build-docs.py | 7 + src/conftest_inputtest.py | 16 - src/conftest_test.py | 57 - src/doc/en/developer/packaging.rst | 4 - src/doc/en/developer/portability_testing.rst | 2 +- src/doc/en/prep/Logging-On.rst | 2 +- src/doc/en/prep/Programming.rst | 2 +- .../en/prep/Symbolics-and-Basic-Plotting.rst | 2 +- src/doc/meson.build | 8 + src/meson.build | 21 +- .../algebras/clifford_algebra_element.pyi | 29 + .../algebras/exterior_algebra_groebner.pyi | 44 + src/sage/algebras/weyl_algebra.py | 549 +++++++- src/sage/arith/functions.pyi | 6 + src/sage/arith/misc.py | 8 +- src/sage/arith/rational_reconstruction.pyi | 3 + src/sage/calculus/calculus.py | 4 +- src/sage/categories/crystals.py | 2 +- src/sage/categories/modules.py | 3 +- src/sage/categories/primer.py | 1 + src/sage/cli/notebook_cmd_test.py | 4 +- src/sage/combinat/matrices/dancing_links.pyx | 3 - src/sage/combinat/rsk.py | 2 + src/sage/combinat/sf/classical.py | 2 +- src/sage/crypto/block_cipher/des.py | 17 +- src/sage/doctest/test.py | 4 +- src/sage/env.py | 1 + src/sage/ext_data/nbconvert/postprocess.py | 2 +- src/sage/graphs/base/c_graph.pyx | 129 ++ .../graphs/base/static_sparse_backend.pyx | 36 - src/sage/graphs/generators/families.py | 5 +- src/sage/graphs/graph.py | 1 - src/sage/graphs/path_enumeration.pyx | 155 ++- src/sage/graphs/strongly_regular_db.pyx | 2 +- src/sage/groups/affine_gps/affine_group.py | 14 + src/sage/groups/perm_gps/permgroup.py | 10 +- src/sage/interfaces/axiom.py | 33 +- src/sage/interfaces/gap.py | 43 +- src/sage/interfaces/giac.py | 18 +- src/sage/interfaces/gp.py | 2 +- src/sage/interfaces/lie.py | 17 +- src/sage/interfaces/lisp.py | 11 +- src/sage/interfaces/macaulay2.py | 22 +- src/sage/interfaces/maple.py | 15 +- src/sage/interfaces/maxima.py | 20 +- src/sage/interfaces/maxima_lib.py | 36 +- src/sage/interfaces/octave.py | 9 +- src/sage/interfaces/polymake.py | 1 + src/sage/interfaces/r.py | 18 +- src/sage/interfaces/sage0.py | 2 +- src/sage/interfaces/singular.py | 43 +- src/sage/libs/ecl.pyx | 8 +- src/sage/libs/meson.build | 77 +- src/sage/libs/singular/ring.pyx | 2 +- src/sage/matrix/matrix0.pxd | 1 + src/sage/matrix/matrix0.pyx | 22 + src/sage/matrix/matrix1.pyx | 6 +- src/sage/matrix/matrix2.pyx | 18 +- src/sage/matrix/matrix_complex_ball_dense.pyx | 78 ++ src/sage/matrix/matrix_cyclo_dense.pyx | 47 + src/sage/matrix/matrix_dense.pyx | 4 +- src/sage/matrix/matrix_gap.pyx | 74 + src/sage/matrix/matrix_generic_dense.pyx | 41 + src/sage/matrix/matrix_generic_sparse.pyx | 44 + src/sage/matrix/matrix_gf2e_dense.pyx | 41 + src/sage/matrix/matrix_gfpn_dense.pyx | 41 + src/sage/matrix/matrix_integer_dense.pyx | 42 + src/sage/matrix/matrix_integer_sparse.pyx | 45 + src/sage/matrix/matrix_mod2_dense.pyx | 62 +- src/sage/matrix/matrix_modn_dense_double.pyx | 42 + src/sage/matrix/matrix_modn_dense_float.pyx | 40 + src/sage/matrix/matrix_modn_sparse.pyx | 40 + src/sage/matrix/matrix_numpy_dense.pyx | 77 +- src/sage/matrix/matrix_rational_dense.pyx | 40 + src/sage/matrix/matrix_rational_sparse.pyx | 43 + src/sage/matrix/matrix_sparse.pyx | 4 +- src/sage/matroids/matroid.pyx | 2 - src/sage/meson.build | 21 +- src/sage/misc/c3_controlled.pyx | 2 +- src/sage/misc/lazy_attribute.pyx | 2 +- src/sage/misc/lazy_import.pxd | 12 + src/sage/misc/lazy_import.pyx | 9 - src/sage/misc/meson.build | 1 + src/sage/misc/persist.pyx | 6 +- src/sage/misc/sageinspect.py | 2 +- ...free_quadratic_module_integer_symmetric.py | 6 +- src/sage/numerical/mip.pyx | 102 +- src/sage/quadratic_forms/bqf_class_group.py | 54 +- .../rings/finite_rings/hom_finite_field.pyx | 2 +- .../rings/function_field/function_field.py | 24 +- .../function_field/function_field_test.py | 116 ++ src/sage/rings/function_field/meson.build | 1 + src/sage/sets/disjoint_set.pyx | 8 +- src/sage/structure/category_object.pyx | 6 +- src/sage/structure/factory.pyx | 2 +- src/sage/structure/list_clone.pyx | 4 +- src/sage/symbolic/expression.pyx | 12 + src/sage/symbolic/function.pyx | 12 +- src/sage/symbolic/getitem_impl.pxi | 2 +- src/sage/symbolic/pynac_function_impl.pxi | 2 +- src/sage/symbolic/pynac_impl.pxi | 16 +- src/sage/symbolic/random_tests.py | 3 +- src/sage/symbolic/ring.pyx | 7 +- src/sage/version.py | 6 +- src/sage_docbuild/ext/sage_autodoc.py | 1232 +++++++++++------ src/sage_setup/cython_options.py | 6 +- src/setup.cfg.m4 | 1 - subprojects/maxima.wrap | 12 + subprojects/packagefiles/ecl/src/meson.build | 22 +- .../packagefiles/maxima/configure.patch | 22 + subprojects/packagefiles/maxima/meson.build | 43 + uv.lock | 8 +- 205 files changed, 4059 insertions(+), 1580 deletions(-) delete mode 100644 build/pkgs/qhull/patches/qhull_cmake.patch create mode 100644 build/pkgs/roman_numerals_py/SPKG.rst create mode 100644 build/pkgs/roman_numerals_py/checksums.ini create mode 100644 build/pkgs/roman_numerals_py/dependencies create mode 100644 build/pkgs/roman_numerals_py/distros/arch.txt create mode 100644 build/pkgs/roman_numerals_py/distros/conda.txt create mode 100644 build/pkgs/roman_numerals_py/distros/fedora.txt create mode 100644 build/pkgs/roman_numerals_py/distros/freebsd.txt create mode 100644 build/pkgs/roman_numerals_py/distros/gentoo.txt create mode 100644 build/pkgs/roman_numerals_py/distros/macports.txt create mode 100644 build/pkgs/roman_numerals_py/distros/opensuse.txt create mode 100644 build/pkgs/roman_numerals_py/package-version.txt create mode 100644 build/pkgs/roman_numerals_py/spkg-configure.m4 create mode 100644 build/pkgs/roman_numerals_py/type create mode 100644 build/pkgs/roman_numerals_py/version_requirements.txt create mode 100644 meson.options delete mode 100755 src/bin/sage-python delete mode 100644 src/conftest_inputtest.py delete mode 100644 src/conftest_test.py create mode 100644 src/sage/algebras/clifford_algebra_element.pyi create mode 100644 src/sage/algebras/exterior_algebra_groebner.pyi create mode 100644 src/sage/arith/functions.pyi create mode 100644 src/sage/arith/rational_reconstruction.pyi create mode 100644 src/sage/misc/lazy_import.pxd create mode 100644 src/sage/rings/function_field/function_field_test.py create mode 100644 subprojects/maxima.wrap create mode 100644 subprojects/packagefiles/maxima/configure.patch create mode 100644 subprojects/packagefiles/maxima/meson.build diff --git a/CITATION.cff b/CITATION.cff index 9f46304e67a..9e78c690650 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.7.beta9 +version: 10.7.rc0 doi: 10.5281/zenodo.8042260 -date-released: 2025-07-25 +date-released: 2025-08-02 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index 0fc91e9c22a..66dda4cb1a5 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.7.beta9, Release Date: 2025-07-25 +SageMath version 10.7.rc0, Release Date: 2025-08-02 diff --git a/build/bin/sage-print-system-package-command b/build/bin/sage-print-system-package-command index f561f1e4436..e1cb44f8eff 100755 --- a/build/bin/sage-print-system-package-command +++ b/build/bin/sage-print-system-package-command @@ -145,6 +145,7 @@ case $system:$command in @(debian*|ubuntu*):*) [ "$NO_INSTALL_RECOMMENDS" = yes ] && options="$options --no-install-recommends" [ "$YES" = yes ] && options="$options --yes" env="DEBIAN_FRONTEND=noninteractive " + # There is an --ignore-missing option for apt-get, but it only ignores download errors not completely missing packages. if [ "$IGNORE_MISSING" = yes ]; then [ -n "$system_packages" ] && echo "for pkg in $system_packages; do ${SUDO}${env}apt-get $command $options \$pkg || true; done" else diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 07f09f85107..c272674364e 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=4c9aecce436e09a96fa3358fce94e4732c56982b -sha256=8b48d72d7ed68b2b17550fb3dabd30437536b040cadc7662d667d2cb5fa53173 +sha1=eb43008c539589aa31cdb6ec98b47a2c43c60486 +sha256=3f7b71621144bf2c62983c5276e00fe941e2be8f33005ae4594c269b71bccd1b diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 26facc6a3b9..270b871436b 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -a1fb267e04a39b64e714b1b97ca625eef075f4d4 +1e5e8e6b859ca8064b05738793074b5695012653 diff --git a/build/pkgs/gap_packages/spkg-install.in b/build/pkgs/gap_packages/spkg-install.in index 314a784c5c7..c67a1176a69 100644 --- a/build/pkgs/gap_packages/spkg-install.in +++ b/build/pkgs/gap_packages/spkg-install.in @@ -92,7 +92,7 @@ install_compiled_pkg() # # These packages have an old ./configure that take the GAP_ROOT as a positional # argument -for pkg in cohomolo crypting grape orb datastructures +for pkg in cohomolo crypting grape guava orb datastructures do echo "Building GAP package $pkg" CFLAGS="$CFLAGS -Wno-implicit-function-declaration" @@ -104,14 +104,6 @@ do cd "$PKG_SRC_DIR" done -echo "Building GAP package guava" -export CFLAGS="-std=gnu17 $CFLAGS -Wno-implicit-function-declaration" -cd "$PKG_SRC_DIR/guava" -./configure "$GAP_ROOT" -sdh_make -install_compiled_pkg "guava" -cd "$PKG_SRC_DIR" - # These packages have a new-style autoconf ./configure # that takes --with-gaproot diff --git a/build/pkgs/ncurses/distros/debian.txt b/build/pkgs/ncurses/distros/debian.txt index 93d362aa240..9819e5e1174 100644 --- a/build/pkgs/ncurses/distros/debian.txt +++ b/build/pkgs/ncurses/distros/debian.txt @@ -1 +1 @@ -libncurses5-dev +libncurses-dev diff --git a/build/pkgs/polymake/checksums.ini b/build/pkgs/polymake/checksums.ini index 3173f176491..c2b02ee12a4 100644 --- a/build/pkgs/polymake/checksums.ini +++ b/build/pkgs/polymake/checksums.ini @@ -1,4 +1,5 @@ tarball=polymake-VERSION-minimal.tar.bz2 -sha1=aa1a153fac97a9faad61842f4a4232fbf444155f -sha256=bd5a667ffca4bf7eb8d51134030ce3df3b16dd9d0e800fafdb1ce835867640d9 +sha1=03b0916fe2847d9a234c7ced72e25ab268c3dd78 +sha256=e27667719a59102c1b27f5f98fa83cd3b4147f63292940592f217151defdbf8d upstream_url=https://polymake.org/lib/exe/fetch.php/download/polymake-VERSION-minimal.tar.bz2 + diff --git a/build/pkgs/polymake/package-version.txt b/build/pkgs/polymake/package-version.txt index f5885845348..d4505b87e24 100644 --- a/build/pkgs/polymake/package-version.txt +++ b/build/pkgs/polymake/package-version.txt @@ -1 +1 @@ -4.12 +4.14 diff --git a/build/pkgs/qhull/patches/qhull_cmake.patch b/build/pkgs/qhull/patches/qhull_cmake.patch deleted file mode 100644 index fd98a127f40..00000000000 --- a/build/pkgs/qhull/patches/qhull_cmake.patch +++ /dev/null @@ -1,22 +0,0 @@ -*** src/CMakeLists.txt.orig Thu May 8 13:21:24 2025 ---- src/CMakeLists.txt Thu May 8 13:25:39 2025 -*************** -*** 67,74 **** - # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ - # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ - - project(qhull) -- cmake_minimum_required(VERSION 3.0) - - # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt - # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm ---- 67,75 ---- - # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ - # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ - -+ cmake_minimum_required(VERSION 3.25...4.0.3) -+ - project(qhull) - - # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt - # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm diff --git a/build/pkgs/roman_numerals_py/SPKG.rst b/build/pkgs/roman_numerals_py/SPKG.rst new file mode 100644 index 00000000000..b7ed999c753 --- /dev/null +++ b/build/pkgs/roman_numerals_py/SPKG.rst @@ -0,0 +1,26 @@ +Roman-numerals-py: Manipulate well-formed Roman numerals +======================================================== + +Description +----------- + +A library for manipulating well-formed Roman numerals. + +Integers between 1 and 3,999 (inclusive) are supported. Numbers beyond +this range will return an OutOfRangeError. + +The classical system of roman numerals requires that the same character +may not appear more than thrice consecutively, meaning that ‘MMMCMXCIX’ +(3,999) is the largest well-formed Roman numeral. The smallest is ‘I’ (1), +as there is no symbol for zero in Roman numerals. + +License +------- + +This project is licenced under the terms of either the Zero-Clause +BSD licence or the CC0 1.0 Universal licence + +Upstream Contact +---------------- + +https://pypi.org/project/roman-numerals-py/ diff --git a/build/pkgs/roman_numerals_py/checksums.ini b/build/pkgs/roman_numerals_py/checksums.ini new file mode 100644 index 00000000000..d75dc72c4cd --- /dev/null +++ b/build/pkgs/roman_numerals_py/checksums.ini @@ -0,0 +1,4 @@ +tarball=roman_numerals_py-VERSION-py3-none-any.whl +sha1=1d5e23a0ba8e244bf800597eaef15741d4cfeb0b +sha256=9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c +upstream_url=https://files.pythonhosted.org/packages/py3/r/roman_numerals_py/roman_numerals_py-VERSION-py3-none-any.whl diff --git a/build/pkgs/roman_numerals_py/dependencies b/build/pkgs/roman_numerals_py/dependencies new file mode 100644 index 00000000000..47296a7bace --- /dev/null +++ b/build/pkgs/roman_numerals_py/dependencies @@ -0,0 +1,4 @@ + | $(PYTHON_TOOLCHAIN) $(PYTHON) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/roman_numerals_py/distros/arch.txt b/build/pkgs/roman_numerals_py/distros/arch.txt new file mode 100644 index 00000000000..b2ef9701eaa --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/arch.txt @@ -0,0 +1 @@ +python-roman-numerals-py diff --git a/build/pkgs/roman_numerals_py/distros/conda.txt b/build/pkgs/roman_numerals_py/distros/conda.txt new file mode 100644 index 00000000000..d303e56002e --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/conda.txt @@ -0,0 +1 @@ +roman-numerals-py diff --git a/build/pkgs/roman_numerals_py/distros/fedora.txt b/build/pkgs/roman_numerals_py/distros/fedora.txt new file mode 100644 index 00000000000..b2ef9701eaa --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/fedora.txt @@ -0,0 +1 @@ +python-roman-numerals-py diff --git a/build/pkgs/roman_numerals_py/distros/freebsd.txt b/build/pkgs/roman_numerals_py/distros/freebsd.txt new file mode 100644 index 00000000000..ecf05970180 --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/freebsd.txt @@ -0,0 +1 @@ +textproc/py-roman-numerals-py diff --git a/build/pkgs/roman_numerals_py/distros/gentoo.txt b/build/pkgs/roman_numerals_py/distros/gentoo.txt new file mode 100644 index 00000000000..3d486edbbff --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/roman-numerals-py diff --git a/build/pkgs/roman_numerals_py/distros/macports.txt b/build/pkgs/roman_numerals_py/distros/macports.txt new file mode 100644 index 00000000000..55992ca1dfa --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/macports.txt @@ -0,0 +1 @@ +py-roman-_numerals_py diff --git a/build/pkgs/roman_numerals_py/distros/opensuse.txt b/build/pkgs/roman_numerals_py/distros/opensuse.txt new file mode 100644 index 00000000000..15821954064 --- /dev/null +++ b/build/pkgs/roman_numerals_py/distros/opensuse.txt @@ -0,0 +1 @@ +python-roman-numerals diff --git a/build/pkgs/roman_numerals_py/package-version.txt b/build/pkgs/roman_numerals_py/package-version.txt new file mode 100644 index 00000000000..fd2a01863fd --- /dev/null +++ b/build/pkgs/roman_numerals_py/package-version.txt @@ -0,0 +1 @@ +3.1.0 diff --git a/build/pkgs/roman_numerals_py/spkg-configure.m4 b/build/pkgs/roman_numerals_py/spkg-configure.m4 new file mode 100644 index 00000000000..303ca75e7bb --- /dev/null +++ b/build/pkgs/roman_numerals_py/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([roman-numericals-py], [ + SAGE_PYTHON_PACKAGE_CHECK([roman-numericals-py]) +]) diff --git a/build/pkgs/roman_numerals_py/type b/build/pkgs/roman_numerals_py/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/roman_numerals_py/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/roman_numerals_py/version_requirements.txt b/build/pkgs/roman_numerals_py/version_requirements.txt new file mode 100644 index 00000000000..d303e56002e --- /dev/null +++ b/build/pkgs/roman_numerals_py/version_requirements.txt @@ -0,0 +1 @@ +roman-numerals-py diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index 65a43f1cf31..40372d14823 100644 --- a/build/pkgs/sage_conf/version_requirements.txt +++ b/build/pkgs/sage_conf/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sage-conf ~= 10.7b9 +sage-conf ~= 10.7rc0 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index f09ac9b7c47..cefcc11aa97 100644 --- a/build/pkgs/sage_docbuild/version_requirements.txt +++ b/build/pkgs/sage_docbuild/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sage-docbuild ~= 10.7b9 +sage-docbuild ~= 10.7rc0 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index 31176b46afd..fa0b379be55 100644 --- a/build/pkgs/sage_setup/version_requirements.txt +++ b/build/pkgs/sage_setup/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sage-setup ~= 10.7b9 +sage-setup ~= 10.7rc0 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index 449862c0a34..9c1f7167c51 100644 --- a/build/pkgs/sagelib/version_requirements.txt +++ b/build/pkgs/sagelib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-standard ~= 10.7b9 +sagemath-standard ~= 10.7rc0 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index cd2bec7b26b..be802388912 100644 --- a/build/pkgs/sagemath_bliss/version_requirements.txt +++ b/build/pkgs/sagemath_bliss/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-bliss ~= 10.7b9 +sagemath-bliss ~= 10.7rc0 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index d2c0cb34c18..b3245c5403e 100644 --- a/build/pkgs/sagemath_categories/version_requirements.txt +++ b/build/pkgs/sagemath_categories/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-categories ~= 10.7b9 +sagemath-categories ~= 10.7rc0 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index f129052cbc6..2f209292f56 100644 --- a/build/pkgs/sagemath_coxeter3/version_requirements.txt +++ b/build/pkgs/sagemath_coxeter3/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-coxeter3 ~= 10.7b9 +sagemath-coxeter3 ~= 10.7rc0 diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 929d1bf5af6..302f4887b7c 100644 --- a/build/pkgs/sagemath_environment/version_requirements.txt +++ b/build/pkgs/sagemath_environment/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-environment ~= 10.7b9 +sagemath-environment ~= 10.7rc0 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index 424eef29acc..cd47e9e5d28 100644 --- a/build/pkgs/sagemath_mcqd/version_requirements.txt +++ b/build/pkgs/sagemath_mcqd/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-mcqd ~= 10.7b9 +sagemath-mcqd ~= 10.7rc0 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index c736108a377..5aba6aa9418 100644 --- a/build/pkgs/sagemath_meataxe/version_requirements.txt +++ b/build/pkgs/sagemath_meataxe/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-meataxe ~= 10.7b9 +sagemath-meataxe ~= 10.7rc0 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index 73e8217ca23..04147dbbaa1 100644 --- a/build/pkgs/sagemath_objects/version_requirements.txt +++ b/build/pkgs/sagemath_objects/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-objects ~= 10.7b9 +sagemath-objects ~= 10.7rc0 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index 3f1351efad6..787429f56fe 100644 --- a/build/pkgs/sagemath_repl/version_requirements.txt +++ b/build/pkgs/sagemath_repl/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-repl ~= 10.7b9 +sagemath-repl ~= 10.7rc0 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index aa495009f64..30452b931c1 100644 --- a/build/pkgs/sagemath_sirocco/version_requirements.txt +++ b/build/pkgs/sagemath_sirocco/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-sirocco ~= 10.7b9 +sagemath-sirocco ~= 10.7rc0 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index 9bd1b060799..64a923f2b66 100644 --- a/build/pkgs/sagemath_tdlib/version_requirements.txt +++ b/build/pkgs/sagemath_tdlib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the update-version script -sagemath-tdlib ~= 10.7b9 +sagemath-tdlib ~= 10.7rc0 diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index d6d0de6b17a..25f987a30ea 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -1,4 +1,4 @@ tarball=sphinx-VERSION-py3-none-any.whl -sha1=67dc18611c44f712539585db41aaee4b0a7ec646 -sha256=09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2 +sha1=6c55f99af821939e006411bf4a6ea35ecf6fd5a0 +sha256=4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3 upstream_url=https://files.pythonhosted.org/packages/py3/s/sphinx/sphinx-VERSION-py3-none-any.whl diff --git a/build/pkgs/sphinx/dependencies b/build/pkgs/sphinx/dependencies index 9b7505c9aec..dd3e43e2d67 100644 --- a/build/pkgs/sphinx/dependencies +++ b/build/pkgs/sphinx/dependencies @@ -1,4 +1,4 @@ - | $(PYTHON_TOOLCHAIN) docutils jinja2 pygments snowballstemmer imagesize babel alabaster requests sphinxcontrib_websupport sphinxcontrib_applehelp sphinxcontrib_devhelp sphinxcontrib_htmlhelp sphinxcontrib_jsmath sphinxcontrib_qthelp sphinxcontrib_serializinghtml packaging importlib_metadata $(PYTHON) + | $(PYTHON_TOOLCHAIN) docutils jinja2 pygments snowballstemmer imagesize babel alabaster requests roman_numerals_py sphinxcontrib_websupport sphinxcontrib_applehelp sphinxcontrib_devhelp sphinxcontrib_htmlhelp sphinxcontrib_jsmath sphinxcontrib_qthelp sphinxcontrib_serializinghtml packaging importlib_metadata $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinx/package-version.txt b/build/pkgs/sphinx/package-version.txt index 406b8982770..1365b9236b1 100644 --- a/build/pkgs/sphinx/package-version.txt +++ b/build/pkgs/sphinx/package-version.txt @@ -1 +1 @@ -8.1.3 +8.2.3 diff --git a/build/pkgs/sphinx/version_requirements.txt b/build/pkgs/sphinx/version_requirements.txt index d311e5262f2..39f7ccd4230 100644 --- a/build/pkgs/sphinx/version_requirements.txt +++ b/build/pkgs/sphinx/version_requirements.txt @@ -1 +1 @@ -sphinx >=7.4.7, <9 +sphinx >=8.2.0, <9 diff --git a/build/pkgs/symengine/checksums.ini b/build/pkgs/symengine/checksums.ini index 35f51ec6115..72907d5595e 100644 --- a/build/pkgs/symengine/checksums.ini +++ b/build/pkgs/symengine/checksums.ini @@ -1,4 +1,4 @@ tarball=symengine-VERSION.tar.gz -sha1=e53aa2677bcad5a5dc075a94d4a4f9ef95b5fe07 -sha256=11c5f64e9eec998152437f288b8429ec001168277d55f3f5f1df78e3cf129707 +sha1=2dfee07108509963f3dbe3d9cad9de76d85e551f +sha256=f6972acd6a65354f6414e69460d2e175729470632bdac05919bc2f7f32e48cbd upstream_url=https://github.com/symengine/symengine/releases/download/vVERSION/symengine-VERSION.tar.gz diff --git a/build/pkgs/symengine/package-version.txt b/build/pkgs/symengine/package-version.txt index a803cc227fe..a8839f70de0 100644 --- a/build/pkgs/symengine/package-version.txt +++ b/build/pkgs/symengine/package-version.txt @@ -1 +1 @@ -0.14.0 +0.11.2 \ No newline at end of file diff --git a/build/pkgs/symmetrica/distros/debian.txt b/build/pkgs/symmetrica/distros/debian.txt index f92d7aa6b4a..5148a11b329 100644 --- a/build/pkgs/symmetrica/distros/debian.txt +++ b/build/pkgs/symmetrica/distros/debian.txt @@ -1 +1 @@ -libsymmetrica2-dev +libsymmetrica-dev diff --git a/conftest.py b/conftest.py index 5307d7f6233..98fc948afa7 100644 --- a/conftest.py +++ b/conftest.py @@ -198,10 +198,6 @@ def pytest_collect_file( # This is an executable file. return IgnoreCollector.from_parent(parent) - if file_path.name == "conftest_inputtest.py": - # This is an input file for testing the doctest machinery (and contains broken doctests). - return IgnoreCollector.from_parent(parent) - if ( ( file_path.name == "finite_dimensional_lie_algebras_with_basis.py" diff --git a/environment-3.11-linux-aarch64.yml b/environment-3.11-linux-aarch64.yml index 5a71b26535e..8f5f7b6f3d5 100644 --- a/environment-3.11-linux-aarch64.yml +++ b/environment-3.11-linux-aarch64.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: linux-aarch64 -# input_hash: 92f0a9ce6ce77a42f2e95ee1e91c0141830f89667f0c8fd0992fba010884cd3b +# input_hash: 426d2b0e37f5b24d02e6628c7dfba19de0fd221aa4527460d34fcd79ee3f8519 channels: - conda-forge @@ -14,6 +14,7 @@ dependencies: - appdirs=1.4.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_h6fc4d3a_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321hbecfd40_1 - automake=1.17=pl5321h8af1aa0_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -21,11 +22,13 @@ dependencies: - backports.tarfile=1.2.0=pyhd8ed1ab_1 - bdw-gc=8.2.8=h5ad3122_2 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils=2.44=hf1166c9_0 - - binutils_impl_linux-aarch64=2.44=h4c662bb_0 - - binutils_linux-aarch64=2.44=hf1166c9_0 + - binutils=2.44=hf1166c9_1 + - binutils_impl_linux-aarch64=2.44=h4c662bb_1 + - binutils_linux-aarch64=2.44=hf1166c9_1 - blas=2.132=openblas - blas-devel=3.9.0=32_h9678261_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h2a328a1_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=hdad291f_4 @@ -37,12 +40,12 @@ dependencies: - bzip2=1.0.8=h68df207_7 - c-ares=1.34.5=h86ecc28_0 - c-compiler=1.10.0=h6561dab_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h83712da_0 - cddlib=1!0.94m=h719063d_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py311h14e8bb7_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - click=8.2.1=pyh707e725_0 @@ -66,10 +69,11 @@ dependencies: - cysignals=1.12.3=py311h89d996e_0 - cython=3.1.2=py311hc8540bd_2 - dbus=1.13.6=h12b9eeb_3 - - debugpy=1.8.14=py311h89d996e_0 + - debugpy=1.8.15=py311h8e4e6a5_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=h5ad3122_0 - dulwich=0.22.8=py311h0ca61a2_0 @@ -80,7 +84,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h5ad3122_0 + - expat=2.7.1=hfae3067_0 - fflas-ffpack=2.5.0=h503e619_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -92,7 +96,7 @@ dependencies: - fontconfig=2.15.0=h8dda3cd_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py311h58d527c_0 + - fonttools=4.59.0=py311h164a683_0 - fortran-compiler=1.10.0=h25a59a9_0 - fplll=5.5.0=h45c7457_0 - fpylll=0.6.3=py311h2dc1a0e_0 @@ -139,21 +143,25 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jeepney=0.9.0=pyhd8ed1ab_0 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h05a177a_18 + - kernel-headers_linux-aarch64=4.18.0=h05a177a_8 - keyring=25.6.0=pyha804496_0 - keyutils=1.6.1=h4e544f5_0 - kiwisolver=1.4.8=py311h75754e6_1 - krb5=1.21.3=h50a48e9_0 - lcalc=2.1.0=h30a6b3d_1 - lcms2=2.17=hc88f144_0 - - ld_impl_linux-aarch64=2.44=h5e2c951_0 + - ld_impl_linux-aarch64=2.44=h5e2c951_1 - lerc=4.0.0=hfdc4d58_1 - libblas=3.9.0=32_h1a9f1db_openblas - libboost=1.85.0=h9fa81b4_4 @@ -165,8 +173,8 @@ dependencies: - libbrotlidec=1.1.0=h86ecc28_3 - libbrotlienc=1.1.0=h86ecc28_3 - libcblas=3.9.0=32_hab92f65_openblas - - libclang-cpp20.1=20.1.7=default_h7d4303a_0 - - libclang13=20.1.7=default_h9e36cb9_0 + - libclang-cpp20.1=20.1.8=default_hf07bfb7_0 + - libclang13=20.1.8=default_h173080d_0 - libcups=2.3.3=h5cdc715_5 - libcurl=8.14.1=h6702fde_0 - libdeflate=1.24=he377734_0 @@ -174,7 +182,7 @@ dependencies: - libedit=3.1.20250104=pl5321h976ea20_0 - libegl=1.7.0=hd24410f_2 - libev=4.33=h31becfc_2 - - libexpat=2.7.0=h5ad3122_0 + - libexpat=2.7.1=hfae3067_0 - libffi=3.4.6=he21f813_1 - libflint=3.2.2=hd878b8d_0 - libfreetype=2.13.3=h8af1aa0_1 @@ -196,7 +204,7 @@ dependencies: - libjpeg-turbo=3.1.0=h86ecc28_0 - liblapack=3.9.0=32_h411afd4_openblas - liblapacke=3.9.0=32_hc659ca5_openblas - - libllvm20=20.1.7=h07bd352_0 + - libllvm20=20.1.8=h2b567e5_0 - liblzma=5.8.1=h86ecc28_2 - liblzma-devel=5.8.1=h86ecc28_2 - libnghttp2=1.64.0=hc8609a4_0 @@ -209,19 +217,19 @@ dependencies: - libpq=17.5=hf590da8_0 - libsanitizer=13.3.0=ha58e236_2 - libsodium=1.0.20=h68df207_0 - - libsqlite=3.50.2=he2a92bd_0 + - libsqlite=3.50.3=h022381a_1 - libssh2=1.11.1=h18c354c_0 - libstdcxx=15.1.0=h3f4de04_3 - libstdcxx-devel_linux-aarch64=13.3.0=h0c07274_102 - libstdcxx-ng=15.1.0=hf1166c9_3 - libtiff=4.7.0=h7c15681_5 - libuuid=2.38.1=hb4cce97_0 - - libwebp-base=1.5.0=h0886dbf_0 + - libwebp-base=1.6.0=ha2e29f5_0 - libxcb=1.17.0=h262b8f6_0 - libxcrypt=4.4.36=h31becfc_1 - libxkbcommon=1.10.0=hbab7b08_0 - libxml2=2.13.8=he060846_0 - - libxslt=1.1.39=h1cc9640_0 + - libxslt=1.1.43=h4552c8e_0 - libzlib=1.3.1=h86ecc28_2 - linbox=1.7.0=h8d1c19e_2 - lrcalc=2.1=h5ad3122_7 @@ -238,6 +246,7 @@ dependencies: - memory-allocator=0.1.3=py311ha879c10_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h783934e_1 - mpfi=1.5.4=h846f343_1001 @@ -246,18 +255,25 @@ dependencies: - msgpack-python=1.1.1=py311hc07b1fb_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=h86ecc28_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=ha32ae93_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=ha6136e2_0 + - ninja=1.13.1=hdc560ac_0 - ntl=11.4.3=h0d7519b_1 - - numpy=2.3.1=py311h295a533_0 + - numpy=2.3.1=py311h669026d_1 - openblas=0.3.30=pthreads_h3a8cbd8_0 - openjpeg=2.5.3=h3f56577_0 - openldap=2.6.10=h30c48ee_0 - openssl=3.5.1=hd08dc88_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=hb9de7d4_0 + - pandoc=3.7.0.2=h8af1aa0_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.3=h1e6a6fd_1 - pari=2.17.2=h45cace7_4_pthread - pari-elldata=0.0.20161017=0 @@ -271,7 +287,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py311ha4eaa5e_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h86a87f0_0 + - pixman=0.46.4=h3945e86_0 - pkg-config=0.29.2=hce167ba_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -314,7 +330,7 @@ dependencies: - python-lrcalc=2.1=py311h89d996e_7 - python-symengine=0.14.0=py311h8d73ece_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.11=7_cp311 + - python_abi=3.11=8_cp311 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py311h58d527c_2 - pyzmq=27.0.0=py311h826da9f_0 @@ -325,15 +341,17 @@ dependencies: - r-lattice=0.22_6=r42h25e906a_0 - rapidfuzz=3.13.0=py311h89d996e_0 - readline=8.2=h8382b9d_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py311h38c8ada_0 - rpy2=3.5.11=py311r42hf13da56_3 - ruamel.yaml=0.18.14=py311ha879c10_0 - ruamel.yaml.clib=0.2.8=py311ha879c10_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=h4384887_0 + - ruff=0.12.4=ha8c5b7e_0 - rw=0.9=h31becfc_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -347,7 +365,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=hfdb71ee_1 - sirocco=2.1.0=h7fa4f89_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -361,15 +379,16 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=h1b15455_0 + - sqlite=3.50.3=he8854b5_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h7a35ef0_1 - symmetrica=3.0.1=hd600fc2_0 - sympow=2.023.6=h4d450c3_4 - sympy=1.14.0=pyh2585a3b_105 - - sysroot_linux-aarch64=2.17=h68829e0_18 + - sysroot_linux-aarch64=2.28=h585391f_8 - tachyon=0.99b6=ha0bfc61_1002 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=noxft_h5688188_102 - tktable=2.10=h89546af_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -387,10 +406,11 @@ dependencies: - tzlocal=5.3=py311hec3470c_0 - unicodedata2=16.0.0=py311ha879c10_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h607dc9b_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=hc9499e0_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wayland=1.24.0=h698ed42_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py311ha879c10_0 diff --git a/environment-3.11-linux.yml b/environment-3.11-linux.yml index 78fa7153dee..ea0d4a65452 100644 --- a/environment-3.11-linux.yml +++ b/environment-3.11-linux.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: linux-64 -# input_hash: 9680932a28b59bd770be38a124adb85856e3f6d76c4a78f772fed6ad28ed9fb8 +# input_hash: f2c73a276d552c1cee592849e39d4da886802f0828819a0282888079208c1f48 channels: - conda-forge @@ -16,6 +16,7 @@ dependencies: - appdirs=1.4.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_hf03ea27_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321hbb4ee43_1 - automake=1.17=pl5321ha770c72_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -23,11 +24,13 @@ dependencies: - backports.tarfile=1.2.0=pyhd8ed1ab_1 - bdw-gc=8.2.8=h5888daf_2 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils=2.44=h4852527_0 - - binutils_impl_linux-64=2.44=h4bf12b8_0 - - binutils_linux-64=2.44=h4852527_0 + - binutils=2.44=h4852527_1 + - binutils_impl_linux-64=2.44=h4bf12b8_1 + - binutils_linux-64=2.44=h4852527_1 - blas=2.132=openblas - blas-devel=3.9.0=32_h1ea3ea9_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h00ab1b0_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=h3c6214e_4 @@ -39,12 +42,12 @@ dependencies: - bzip2=1.0.8=h4bc722e_7 - c-ares=1.34.5=hb9d3cd8_0 - c-compiler=1.10.0=h2b85faf_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h3394656_0 - cddlib=1!0.94m=h9202a9a_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py311hf29c0ef_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - click=8.2.1=pyh707e725_0 @@ -68,10 +71,11 @@ dependencies: - cysignals=1.12.3=py311hfdbb021_0 - cython=3.1.2=py311ha3e34f5_2 - dbus=1.16.2=h3c4dab8_0 - - debugpy=1.8.14=py311hfdbb021_0 + - debugpy=1.8.15=py311hc665b79_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=h5888daf_0 - dulwich=0.22.8=py311h9e33e62_0 @@ -82,7 +86,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h5888daf_0 + - expat=2.7.1=hecca717_0 - fflas-ffpack=2.5.0=h4f9960b_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -94,7 +98,7 @@ dependencies: - fontconfig=2.15.0=h7e30c49_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py311h2dc5d0c_0 + - fonttools=4.59.0=py311h3778330_0 - fortran-compiler=1.10.0=h36df796_0 - fplll=5.5.0=hd20a173_0 - fpylll=0.6.3=py311hf0b6740_0 @@ -124,7 +128,7 @@ dependencies: - gxx_impl_linux-64=13.3.0=hae580e1_2 - gxx_linux-64=13.3.0=hb14504d_11 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=h3beb420_0 + - harfbuzz=11.3.2=hbb57e21_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he02047a_0 @@ -141,21 +145,25 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jeepney=0.9.0=pyhd8ed1ab_0 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - - kernel-headers_linux-64=3.10.0=he073ed8_18 + - kernel-headers_linux-64=4.18.0=he073ed8_8 - keyring=25.6.0=pyha804496_0 - keyutils=1.6.1=h166bdaf_0 - kiwisolver=1.4.8=py311hd18a35c_1 - krb5=1.21.3=h659f571_0 - lcalc=2.1.0=h9cf73fc_1 - lcms2=2.17=h717163a_0 - - ld_impl_linux-64=2.44=h1423503_0 + - ld_impl_linux-64=2.44=h1423503_1 - lerc=4.0.0=h0aef613_1 - libblas=3.9.0=32_h59b9bed_openblas - libboost=1.85.0=h0ccab89_4 @@ -167,8 +175,8 @@ dependencies: - libbrotlidec=1.1.0=hb9d3cd8_3 - libbrotlienc=1.1.0=hb9d3cd8_3 - libcblas=3.9.0=32_he106b2a_openblas - - libclang-cpp20.1=20.1.7=default_h1df26ce_0 - - libclang13=20.1.7=default_he06ed0a_0 + - libclang-cpp20.1=20.1.8=default_hddf928d_0 + - libclang13=20.1.8=default_ha444ac7_0 - libcups=2.3.3=hb8b1518_5 - libcurl=8.14.1=h332b0f4_0 - libdeflate=1.24=h86f0d12_0 @@ -176,7 +184,7 @@ dependencies: - libedit=3.1.20250104=pl5321h7949ede_0 - libegl=1.7.0=ha4b6fd6_2 - libev=4.33=hd590300_2 - - libexpat=2.7.0=h5888daf_0 + - libexpat=2.7.1=hecca717_0 - libffi=3.4.6=h2dba641_1 - libflint=3.2.2=h754cb6e_0 - libfreetype=2.13.3=ha770c72_1 @@ -198,7 +206,7 @@ dependencies: - libjpeg-turbo=3.1.0=hb9d3cd8_0 - liblapack=3.9.0=32_h7ac8fdf_openblas - liblapacke=3.9.0=32_he2f377e_openblas - - libllvm20=20.1.7=he9d0ab4_0 + - libllvm20=20.1.8=hecd9e04_0 - liblzma=5.8.1=hb9d3cd8_2 - liblzma-devel=5.8.1=hb9d3cd8_2 - libnghttp2=1.64.0=h161d5f1_0 @@ -211,19 +219,19 @@ dependencies: - libpq=17.5=h27ae623_0 - libsanitizer=13.3.0=he8ea267_2 - libsodium=1.0.20=h4ab18f5_0 - - libsqlite=3.50.2=h6cd9bfd_0 + - libsqlite=3.50.3=hee844dc_1 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.1.0=h8f9b012_3 - libstdcxx-devel_linux-64=13.3.0=hc03c837_102 - libstdcxx-ng=15.1.0=h4852527_3 - libtiff=4.7.0=hf01ce69_5 - libuuid=2.38.1=h0b41bf4_0 - - libwebp-base=1.5.0=h851e524_0 + - libwebp-base=1.6.0=hd42ef1d_0 - libxcb=1.17.0=h8a09558_0 - libxcrypt=4.4.36=hd590300_1 - libxkbcommon=1.10.0=h65c71a3_0 - libxml2=2.13.8=h4bc477f_0 - - libxslt=1.1.39=h76b75d6_0 + - libxslt=1.1.43=h7a3aeb2_0 - libzlib=1.3.1=hb9d3cd8_2 - linbox=1.7.0=h0451620_2 - lrcalc=2.1=h5888daf_7 @@ -241,6 +249,7 @@ dependencies: - memory-allocator=0.1.3=py311h9ecbd09_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h24ddda3_1 - mpfi=1.5.4=h9f54685_1001 @@ -249,18 +258,25 @@ dependencies: - msgpack-python=1.1.1=py311hd18a35c_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=hb9d3cd8_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=h2d0b736_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h7aa8ee6_0 + - ninja=1.13.1=h171cf75_0 - ntl=11.4.3=hef3c4d3_1 - - numpy=2.3.1=py311h519dc76_0 + - numpy=2.3.1=py311h2e04523_1 - openblas=0.3.30=pthreads_h6ec200e_0 - openjpeg=2.5.3=h5fbd93e_0 - openldap=2.6.10=he970967_0 - openssl=3.5.1=h7b32b05_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=h36c2ea0_0 + - pandoc=3.7.0.2=ha770c72_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.4=hadf4263_0 - pari=2.17.2=ha40142e_4_pthread - pari-elldata=0.0.20161017=0 @@ -274,7 +290,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py311h1322bbf_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h29eaf8c_0 + - pixman=0.46.4=h537e5f6_0 - pkg-config=0.29.2=h4bc722e_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -317,7 +333,7 @@ dependencies: - python-lrcalc=2.1=py311hfdbb021_7 - python-symengine=0.14.0=py311h7b351a7_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.11=7_cp311 + - python_abi=3.11=8_cp311 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py311h2dc5d0c_2 - pyzmq=27.0.0=py311h7deb3e3_0 @@ -328,15 +344,17 @@ dependencies: - r-lattice=0.22_6=r42h57805ef_0 - rapidfuzz=3.13.0=py311hfdbb021_0 - readline=8.2=h8c095d6_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py311hdae7d1d_0 - rpy2=3.5.11=py311r42h1f0f07a_3 - ruamel.yaml=0.18.14=py311h9ecbd09_0 - ruamel.yaml.clib=0.2.8=py311h9ecbd09_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=hcc1af86_0 + - ruff=0.12.4=hf9daec2_0 - rw=0.9=hd590300_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -350,7 +368,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=h7ee4ccf_1 - sirocco=2.1.0=hd7ee782_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -364,15 +382,16 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hb7a22d2_0 + - sqlite=3.50.3=heff268d_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h064106a_1 - symmetrica=3.0.1=hcb278e6_0 - sympow=2.023.6=h3028977_4 - sympy=1.14.0=pyh2585a3b_105 - - sysroot_linux-64=2.17=h0157908_18 + - sysroot_linux-64=2.28=h4ee821c_8 - tachyon=0.99b6=hba7d16a_1002 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=noxft_hd72426e_102 - tktable=2.10=h8d826fa_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -390,10 +409,11 @@ dependencies: - tzlocal=5.3=py311h38be061_0 - unicodedata2=16.0.0=py311h9ecbd09_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h29fcd0c_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=heb9285d_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wayland=1.24.0=h3e06ad9_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py311h9ecbd09_0 diff --git a/environment-3.11-macos-x86_64.yml b/environment-3.11-macos-x86_64.yml index 452c20e9950..b8df944378f 100644 --- a/environment-3.11-macos-x86_64.yml +++ b/environment-3.11-macos-x86_64.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: osx-64 -# input_hash: 69739a2f8538e7775c50aef34581f79b5750e3b080249fdf9ec4d21829487063 +# input_hash: 11d7107bfc184e4696e3d368b620d89495fd5a0a9f6bed13a5abb2b204322556 channels: - conda-forge @@ -14,6 +14,7 @@ dependencies: - appnope=0.1.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_hdfe9103_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321had7229c_1 - automake=1.17=pl5321h694c41f_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -23,6 +24,8 @@ dependencies: - beautifulsoup4=4.13.4=pyha770c72_0 - blas=2.132=openblas - blas-devel=3.9.0=32_hbf4f893_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h7728843_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=hfcd56d9_4 @@ -33,31 +36,31 @@ dependencies: - bwidget=1.10.1=h694c41f_1 - bzip2=1.0.8=hfdf4475_7 - c-ares=1.34.5=hf13058a_0 - - c-compiler=1.10.0=h09a7c41_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - c-compiler=1.11.0=h7a00415_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h950ec3b_0 - - cctools=1010.6=ha66f10e_6 - - cctools_osx-64=1010.6=hd19c6af_6 + - cctools=1021.4=h67a6458_1 + - cctools_osx-64=1021.4=haa85c18_1 - cddlib=1!0.94m=h0f52abe_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py311h137bacd_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - - clang=18.1.8=default_h576c50e_10 - - clang-18=18.1.8=default_h3571c67_10 - - clang_impl_osx-64=18.1.8=h6a44ed1_25 - - clang_osx-64=18.1.8=h7e5c614_25 - - clangxx=18.1.8=default_heb2e8d1_10 - - clangxx_impl_osx-64=18.1.8=h4b7810f_25 - - clangxx_osx-64=18.1.8=h7e5c614_25 + - clang=19.1.7=default_h576c50e_3 + - clang-19=19.1.7=default_h3571c67_3 + - clang_impl_osx-64=19.1.7=hc73cdc9_25 + - clang_osx-64=19.1.7=h7e5c614_25 + - clangxx=19.1.7=default_heb2e8d1_3 + - clangxx_impl_osx-64=19.1.7=hb295874_25 + - clangxx_osx-64=19.1.7=h7e5c614_25 - click=8.2.1=pyh707e725_0 - click-default-group=1.2.4=pyhd8ed1ab_1 - cliquer=1.22=h10d778d_1 - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.2=pyhd8ed1ab_1 - - compiler-rt=18.1.8=h1020d70_1 - - compiler-rt_osx-64=18.1.8=hf2b8a54_1 + - compiler-rt=19.1.7=h52031e2_0 + - compiler-rt_osx-64=19.1.7=hc6f8467_0 - conda-lock=3.0.4=pyhb3ed7dc_1 - conda-souschef=2.2.3=pyhd8ed1ab_0 - contourpy=1.3.2=py311h4e34fa0_0 @@ -67,15 +70,16 @@ dependencies: - crashtest=0.4.1=pyhd8ed1ab_1 - cryptography=45.0.5=py311h336e25c_0 - curl=8.14.1=h5dec5d8_0 - - cxx-compiler=1.10.0=h20888b2_0 + - cxx-compiler=1.11.0=h307afc9_0 - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.2.2=py311h29339b9_0 - cysignals=1.12.3=py311hc356e98_0 - cython=3.1.2=py311h3c013cf_2 - - debugpy=1.8.14=py311hc356e98_0 + - debugpy=1.8.15=py311hc651eee_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - dulwich=0.22.8=py311h3b9c2be_0 - ecl=24.5.10=ha6bf567_1 @@ -85,7 +89,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h240833e_0 + - expat=2.7.1=h21dd04a_0 - fflas-ffpack=2.5.0=h5898d61_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -97,7 +101,7 @@ dependencies: - fontconfig=2.15.0=h37eeddb_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py311ha3cf9ac_0 + - fonttools=4.59.0=py311hfbe4617_0 - fortran-compiler=1.10.0=h02557f8_0 - fplll=5.5.0=h6ede486_0 - fpylll=0.6.3=py311h793c761_0 @@ -108,9 +112,9 @@ dependencies: - gap-defaults=4.14.0=h694c41f_5 - gf2x=1.3.0=h35ac7d9_3 - gfan=0.6.2=hd793b56_1003 - - gfortran=13.3.0=hcc3c99d_1 - - gfortran_impl_osx-64=13.3.0=hbf5bf67_105 - - gfortran_osx-64=13.3.0=h3223c34_1 + - gfortran=13.4.0=hcc3c99d_0 + - gfortran_impl_osx-64=13.4.0=h8d0df8b_0 + - gfortran_osx-64=13.4.0=h3223c34_0 - gitdb=4.0.12=pyhd8ed1ab_0 - gitpython=3.1.44=pyhff2d567_0 - givaro=4.2.0=h89f8175_2 @@ -121,7 +125,7 @@ dependencies: - grayskull=2.9.1=pyhd8ed1ab_0 - gsl=2.8=hc707ee6_1 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=hdfbcdba_0 + - harfbuzz=11.3.2=hb258ee5_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=h120a0e1_0 @@ -139,21 +143,25 @@ dependencies: - isl=0.26=imath32_h2e86a7b_101 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh534df25_0 - kiwisolver=1.4.8=py311h4e34fa0_1 - krb5=1.21.3=h37d8d59_0 - lcalc=2.1.0=h0f747f7_1 - lcms2=2.17=h72f5680_0 - - ld64=951.9=h4e51db5_6 - - ld64_osx-64=951.9=h33512f0_6 + - ld64=954.16=hc3792c1_1 + - ld64_osx-64=954.16=hf1c22e8_1 - lerc=4.0.0=hcca01a6_1 - - libasprintf=0.25.1=h27064b9_0 + - libasprintf=0.25.1=h3184127_1 - libblas=3.9.0=32_h7f60823_openblas - libboost=1.85.0=hcca3243_4 - libboost-devel=1.85.0=h2b186f8_4 @@ -164,48 +172,48 @@ dependencies: - libbrotlidec=1.1.0=h6e16a3a_3 - libbrotlienc=1.1.0=h6e16a3a_3 - libcblas=3.9.0=32_hff6cab4_openblas - - libclang-cpp18.1=18.1.8=default_h3571c67_10 + - libclang-cpp19.1=19.1.7=default_h3571c67_3 - libcurl=8.14.1=h5dec5d8_0 - - libcxx=20.1.7=hf95d169_0 - - libcxx-devel=18.1.8=h7c275be_8 + - libcxx=20.1.8=h3d58e20_1 + - libcxx-devel=19.1.7=h7c275be_1 - libdeflate=1.24=hcc1b750_0 - libedit=3.1.20250104=pl5321ha958ccf_0 - libev=4.33=h10d778d_2 - - libexpat=2.7.0=h240833e_0 + - libexpat=2.7.1=h21dd04a_0 - libffi=3.4.6=h281671d_1 - libflint=3.2.2=h26b1ecd_0 - libfreetype=2.13.3=h694c41f_1 - libfreetype6=2.13.3=h40dfd5c_1 - libgd=2.3.3=h8555400_11 - - libgettextpo=0.25.1=h27064b9_0 + - libgettextpo=0.25.1=h3184127_1 - libgfortran=5.0.0=14_2_0_h51e75f0_103 - - libgfortran-devel_osx-64=13.3.0=h297be85_105 + - libgfortran-devel_osx-64=13.4.0=hbfa0f67_0 - libgfortran5=14.2.0=h51e75f0_103 - libglib=2.84.2=h3139dbc_0 - libhomfly=1.02r6=h10d778d_1 - libiconv=1.18=h4b5e92a_1 - - libintl=0.25.1=h27064b9_0 + - libintl=0.25.1=h3184127_1 - libjpeg-turbo=3.1.0=h6e16a3a_0 - liblapack=3.9.0=32_h236ab99_openblas - liblapacke=3.9.0=32_h85686d2_openblas - - libllvm18=18.1.8=hc29ff6c_3 + - libllvm19=19.1.7=hc29ff6c_1 - liblzma=5.8.1=hd471939_2 - liblzma-devel=5.8.1=hd471939_2 - libnghttp2=1.64.0=hc7306c3_0 - libopenblas=0.3.30=openmp_hbf64a52_0 - libpng=1.6.50=h3c4a55f_0 - libsodium=1.0.20=hfdf4475_0 - - libsqlite=3.50.2=he7d56d0_0 + - libsqlite=3.50.3=h875aaf5_1 - libssh2=1.11.1=hed3591d_0 - libtiff=4.7.0=h1167cee_5 - - libwebp-base=1.5.0=h6cf52b4_0 + - libwebp-base=1.6.0=hb807250_0 - libxcb=1.17.0=hf1f96e2_0 - libxml2=2.13.8=h93c44a6_0 - libzlib=1.3.1=hd23fc13_2 - linbox=1.7.0=h1e49b7d_2 - - llvm-openmp=20.1.7=ha54dae1_0 - - llvm-tools=18.1.8=hc29ff6c_3 - - llvm-tools-18=18.1.8=hc29ff6c_3 + - llvm-openmp=20.1.8=hf4e0ed4_0 + - llvm-tools=19.1.7=h3fe3016_1 + - llvm-tools-19=19.1.7=he90a8e3_1 - lrcalc=2.1=hac325c4_7 - lrslib=71.b=hda3377a_1 - m4=1.4.20=h6e16a3a_0 @@ -221,6 +229,7 @@ dependencies: - memory-allocator=0.1.3=py311h3336109_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h9d8efa1_1 - mpfi=1.5.4=h52b28e3_1001 @@ -229,17 +238,24 @@ dependencies: - msgpack-python=1.1.1=py311h4e34fa0_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=h6e16a3a_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=h0622a9a_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h46ed394_0 + - ninja=1.13.1=h0ba0a54_0 - ntl=11.4.3=h0ab3c2f_1 - - numpy=2.3.1=py311h9224382_0 + - numpy=2.3.1=py311h09fcace_1 - openblas=0.3.30=openmp_h30af337_0 - openjpeg=2.5.3=h7fd6d84_0 - openssl=3.5.1=hc426f3f_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=hbcb3906_0 + - pandoc=3.7.0.2=h694c41f_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.4=h6ef8af8_0 - pari=2.17.2=h1ed0f1a_4_pthread - pari-elldata=0.0.20161017=0 @@ -253,7 +269,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py311h25da234_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h1fd1274_0 + - pixman=0.46.4=h6f2c7e4_0 - pkg-config=0.29.2=hf7e621a_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -295,7 +311,7 @@ dependencies: - python-lrcalc=2.1=py311hd89902b_7 - python-symengine=0.14.0=py311hd9f0a9d_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.11=7_cp311 + - python_abi=3.11=8_cp311 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py311ha3cf9ac_2 - pyzmq=27.0.0=py311hb21797c_0 @@ -305,15 +321,17 @@ dependencies: - r-lattice=0.22_6=r42hb2c329c_0 - rapidfuzz=3.13.0=py311hc356e98_0 - readline=8.2=h7cca4af_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py311hd1a56c6_0 - rpy2=3.5.11=py311r42h4a70a88_3 - ruamel.yaml=0.18.14=py311h4d7f069_0 - ruamel.yaml.clib=0.2.8=py311h1314207_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=h8aa17f0_0 + - ruff=0.12.4=h6cc4cfe_0 - rw=0.9=h10d778d_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -326,7 +344,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=haa275bf_1 - sirocco=2.1.0=hfc2cc1e_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -340,7 +358,7 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=h22fafd5_0 + - sqlite=3.50.3=h8d07200_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h79ccd14_1 @@ -349,6 +367,7 @@ dependencies: - sympy=1.14.0=pyh2585a3b_105 - tachyon=0.99b6=h3a1d103_1002 - tapi=1300.6.5=h390ca13_0 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=hf689a15_2 - tktable=2.10=h2c093e9_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -366,13 +385,14 @@ dependencies: - tzlocal=5.3=py311h6eed73b_0 - unicodedata2=16.0.0=py311h4d7f069_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=hb40bb8a_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=hfa71dfd_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py311h4d7f069_0 - - xattr=1.1.0=py311h3336109_1 + - xattr=1.2.0=py311h8e62900_0 - xorg-libxau=1.0.12=h6e16a3a_0 - xorg-libxdmcp=1.1.5=h00291cd_0 - xz=5.8.1=h357f2ed_2 diff --git a/environment-3.11-macos.yml b/environment-3.11-macos.yml index d97181723b3..0d35e7f786a 100644 --- a/environment-3.11-macos.yml +++ b/environment-3.11-macos.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: osx-arm64 -# input_hash: f538de1db1ea949e7cb8ae8d56b0fe67c20233dc9fa766882bc04d6add5fbfd8 +# input_hash: 73494c91508e263c54f41d7613518d1cc5561156a1b692ffef06508c29dd5ce3 channels: - conda-forge @@ -13,6 +13,7 @@ dependencies: - appnope=0.1.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_h1f29f7c_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321hd3c70e0_1 - automake=1.17=pl5321hce30654_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -22,6 +23,8 @@ dependencies: - beautifulsoup4=4.13.4=pyha770c72_0 - blas=2.132=openblas - blas-devel=3.9.0=32_h11c0a38_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h2ffa867_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=h103c1d6_4 @@ -32,22 +35,22 @@ dependencies: - bwidget=1.10.1=hce30654_1 - bzip2=1.0.8=h99b78c6_7 - c-ares=1.34.5=h5505292_0 - - c-compiler=1.10.0=hdf49b6b_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - c-compiler=1.9.0=hdf49b6b_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h6a3b0d2_0 - - cctools=1010.6=hb4fb6a3_6 - - cctools_osx-arm64=1010.6=h3b4f5d3_6 + - cctools=1021.4=hb4fb6a3_0 + - cctools_osx-arm64=1021.4=h12580ec_0 - cddlib=1!0.94m=h6d7a090_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py311h3a79f62_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - - clang=18.1.8=default_h474c9e2_10 - - clang-18=18.1.8=default_hf90f093_10 + - clang=18.1.8=default_h1eedb11_11 + - clang-18=18.1.8=default_h649e436_11 - clang_impl_osx-arm64=18.1.8=h2ae9ea5_25 - clang_osx-arm64=18.1.8=h07b0088_25 - - clangxx=18.1.8=default_h1ffe849_10 + - clangxx=18.1.8=default_h0dcb199_11 - clangxx_impl_osx-arm64=18.1.8=h555f467_25 - clangxx_osx-arm64=18.1.8=h07b0088_25 - click=8.2.1=pyh707e725_0 @@ -66,15 +69,16 @@ dependencies: - crashtest=0.4.1=pyhd8ed1ab_1 - cryptography=45.0.5=py311h8be0713_0 - curl=8.14.1=h73640d1_0 - - cxx-compiler=1.10.0=hba80287_0 + - cxx-compiler=1.9.0=hba80287_0 - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.2.2=py311haabaa81_0 - cysignals=1.12.3=py311h155a34a_0 - cython=3.1.2=py311h71112e5_2 - - debugpy=1.8.14=py311h155a34a_0 + - debugpy=1.8.15=py311ha59bd64_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - dulwich=0.22.8=py311h3ff9189_0 - ecl=24.5.10=hc6c598b_1 @@ -84,7 +88,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h286801f_0 + - expat=2.7.1=hec049ff_0 - fflas-ffpack=2.5.0=h4bc3318_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -96,7 +100,7 @@ dependencies: - fontconfig=2.15.0=h1383a14_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py311h4921393_0 + - fonttools=4.59.0=py311h2fe624c_0 - fortran-compiler=1.10.0=h5692697_0 - fplll=5.5.0=h2a2278a_0 - fpylll=0.6.3=py311h4044dbd_0 @@ -120,7 +124,7 @@ dependencies: - grayskull=2.9.1=pyhd8ed1ab_0 - gsl=2.8=h8d0574d_1 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=hab40de2_0 + - harfbuzz=11.3.2=hcb8449c_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=hfee45f7_0 @@ -138,19 +142,23 @@ dependencies: - isl=0.26=imath32_h347afa1_101 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh534df25_0 - kiwisolver=1.4.8=py311h210dab8_1 - krb5=1.21.3=h237132a_0 - lcalc=2.1.0=hdaf6845_1 - lcms2=2.17=h7eeda09_0 - - ld64=951.9=h4c6efb1_6 - - ld64_osx-arm64=951.9=hb6b49e2_6 + - ld64=954.16=h4c6efb1_0 + - ld64_osx-arm64=954.16=h9d5fcb0_0 - lerc=4.0.0=hd64df32_1 - libasprintf=0.25.1=h493aca8_0 - libblas=3.9.0=32_h10e41b3_openblas @@ -163,14 +171,14 @@ dependencies: - libbrotlidec=1.1.0=h5505292_3 - libbrotlienc=1.1.0=h5505292_3 - libcblas=3.9.0=32_hb3479ef_openblas - - libclang-cpp18.1=18.1.8=default_hf90f093_10 + - libclang-cpp18.1=18.1.8=default_h649e436_11 - libcurl=8.14.1=h73640d1_0 - - libcxx=20.1.7=ha82da77_0 + - libcxx=20.1.8=hf598326_1 - libcxx-devel=18.1.8=h6dc3340_8 - libdeflate=1.24=h5773f1b_0 - libedit=3.1.20250104=pl5321hafb1f1b_0 - libev=4.33=h93a5062_2 - - libexpat=2.7.0=h286801f_0 + - libexpat=2.7.1=hec049ff_0 - libffi=3.4.6=h1da3d7d_1 - libflint=3.2.2=hf825d4a_0 - libfreetype=2.13.3=hce30654_1 @@ -187,24 +195,24 @@ dependencies: - libjpeg-turbo=3.1.0=h5505292_0 - liblapack=3.9.0=32_hc9a63f6_openblas - liblapacke=3.9.0=32_hbb7bcf8_openblas - - libllvm18=18.1.8=hc4b4ae8_3 + - libllvm18=18.1.8=default_h3f49643_6 - liblzma=5.8.1=h39f12f2_2 - liblzma-devel=5.8.1=h39f12f2_2 - libnghttp2=1.64.0=h6d7220d_0 - libopenblas=0.3.30=openmp_hf332438_0 - libpng=1.6.50=h3783ad8_0 - libsodium=1.0.20=h99b78c6_0 - - libsqlite=3.50.2=h6fb428d_0 + - libsqlite=3.50.3=h4237e3c_1 - libssh2=1.11.1=h1590b86_0 - libtiff=4.7.0=h2f21f7c_5 - - libwebp-base=1.5.0=h2471fea_0 + - libwebp-base=1.6.0=h07db88b_0 - libxcb=1.17.0=hdb1d25a_0 - libxml2=2.13.8=h52572c6_0 - libzlib=1.3.1=h8359307_2 - linbox=1.7.0=h66f06df_2 - - llvm-openmp=20.1.7=hdb05f8b_0 - - llvm-tools=18.1.8=hc4b4ae8_3 - - llvm-tools-18=18.1.8=hc4b4ae8_3 + - llvm-openmp=20.1.8=hbb9b287_0 + - llvm-tools=18.1.8=default_h3f49643_6 + - llvm-tools-18=18.1.8=default_h3f49643_6 - lrcalc=2.1=hf9b8971_7 - m4=1.4.20=h5505292_0 - m4ri=20140914=hc97c1ff_1006 @@ -219,6 +227,7 @@ dependencies: - memory-allocator=0.1.3=py311h460d6c5_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h8f1351a_1 - mpfi=1.5.4=hbde5f5b_1001 @@ -227,17 +236,24 @@ dependencies: - msgpack-python=1.1.1=py311h210dab8_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=h5505292_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=h5e97a16_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=ha024513_0 + - ninja=1.13.1=h4f10f1e_0 - ntl=11.4.3=hbb3f309_1 - - numpy=2.3.1=py311h4379d9d_0 + - numpy=2.3.1=py311h0856f98_1 - openblas=0.3.30=openmp_hea878ba_0 - openjpeg=2.5.3=h8a3d83b_0 - openssl=3.5.1=h81ee809_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=h27ca646_0 + - pandoc=3.7.0.2=hce30654_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.4=h875632e_0 - pari=2.17.2=h49d18c7_4_pthread - pari-elldata=0.0.20161017=0 @@ -251,7 +267,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py311hb9ba9e9_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h2f9eb0b_0 + - pixman=0.46.4=h2c80e29_0 - pkg-config=0.29.2=hde07d2e_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -293,7 +309,7 @@ dependencies: - python-lrcalc=2.1=py311h3f08180_7 - python-symengine=0.14.0=py311hef325c5_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.11=7_cp311 + - python_abi=3.11=8_cp311 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py311h4921393_2 - pyzmq=27.0.0=py311h01f2145_0 @@ -303,15 +319,17 @@ dependencies: - r-lattice=0.22_6=r42hd2d937b_0 - rapidfuzz=3.13.0=py311h155a34a_0 - readline=8.2=h1d1bf99_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py311hf245fc6_0 - rpy2=3.5.11=py311r42hb49d859_3 - ruamel.yaml=0.18.14=py311h917b07b_0 - ruamel.yaml.clib=0.2.8=py311hae2e1ce_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=h412e174_0 + - ruff=0.12.4=h575f11b_0 - rw=0.9=h93a5062_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -324,7 +342,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=h837545d_1 - sirocco=2.1.0=h41f8169_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -338,7 +356,7 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hc23dd5f_0 + - sqlite=3.50.3=hb5dd463_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=hddbed1c_1 @@ -347,6 +365,7 @@ dependencies: - sympy=1.14.0=pyh2585a3b_105 - tachyon=0.99b6=hb8a568e_1002 - tapi=1300.6.5=h03f4b80_0 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=h892fb3f_2 - tktable=2.10=h3c7de25_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -364,13 +383,14 @@ dependencies: - tzlocal=5.3=py311h267d04e_0 - unicodedata2=16.0.0=py311h917b07b_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=hcff7401_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=hb521335_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py311h917b07b_0 - - xattr=1.1.0=py311h460d6c5_1 + - xattr=1.2.0=py311h7d51efc_0 - xorg-libxau=1.0.12=h5505292_0 - xorg-libxdmcp=1.1.5=hd74edd7_0 - xz=5.8.1=h9a6d368_2 diff --git a/environment-3.11-win.yml b/environment-3.11-win.yml index 0b86f3dd861..c87bf870403 100644 --- a/environment-3.11-win.yml +++ b/environment-3.11-win.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: win-64 -# input_hash: 4fdb24f38d982c64e642758c2d1bc7cb5650283337eec99d95ba6badde1db52a +# input_hash: c830b395e986a50a0e08ad7519c5c706c16ea5fa1a8cde20d9f2526b7cd7fb03 channels: - conda-forge @@ -12,13 +12,16 @@ dependencies: - annotated-types=0.7.0=pyhd8ed1ab_1 - appdirs=1.4.4=pyhd8ed1ab_1 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - babel=2.17.0=pyhd8ed1ab_0 - backports=1.0=pyhd8ed1ab_5 - backports.tarfile=1.2.0=pyhd8ed1ab_1 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils_impl_win-64=2.44=h095e170_0 + - binutils_impl_win-64=2.44=h095e170_1 - blas=2.132=openblas - blas-devel=3.9.0=32_hc0f8095_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=ha5ead02_4 - brotli=1.1.0=h2466b09_3 @@ -26,11 +29,11 @@ dependencies: - brotli-python=1.1.0=py311hda3d55a_3 - bwidget=1.10.1=h57928b3_1 - bzip2=1.0.8=h2466b09_7 - - ca-certificates=2025.6.15=h4c7d964_0 + - ca-certificates=2025.7.14=h4c7d964_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h5782bbf_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py311he736701_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - clang=19.1.7=default_hec7ea82_3 @@ -53,10 +56,11 @@ dependencies: - cycler=0.12.1=pyhd8ed1ab_1 - cysignals=1.12.3=py311hda3d55a_0 - cython=3.1.2=py311h34f20a9_2 - - debugpy=1.8.14=py311hda3d55a_0 + - debugpy=1.8.15=py311h5dfdfe8_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=he0c23c2_0 - dulwich=0.22.8=py311h533ab2d_0 @@ -64,7 +68,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=he0c23c2_0 + - expat=2.7.1=hac47afa_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 - flake8-rst-docstrings=0.3.1=pyhd8ed1ab_0 @@ -78,8 +82,8 @@ dependencies: - fontconfig=2.15.0=h765892d_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py311h3f79411_0 - - fortran-compiler=1.10.0=h95e3450_0 + - fonttools=4.59.0=py311h3f79411_0 + - fortran-compiler=1.11.0=h95e3450_0 - freetype=2.13.3=h57928b3_1 - furo=2024.8.6=pyhd8ed1ab_2 - gcc_impl_win-64=15.1.0=hb5bc704_3 @@ -94,7 +98,7 @@ dependencies: - gsl=2.7=hdfb1a43_0 - gxx_impl_win-64=15.1.0=h91e354b_3 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=h8796e6f_0 + - harfbuzz=11.3.2=h8796e6f_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he0c23c2_0 @@ -110,17 +114,21 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh5737063_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh7428d3b_0 - kiwisolver=1.4.8=py311h3fd045d_1 - krb5=1.21.3=hdf4eb48_0 - lcms2=2.17=hbcf6048_0 - - ld_impl_win-64=2.44=hae1bf67_0 + - ld_impl_win-64=2.44=hae1bf67_1 - lerc=4.0.0=h6470a55_1 - libblas=3.9.0=32_h11dc60a_openblas - libboost=1.85.0=h444863b_4 @@ -130,10 +138,10 @@ dependencies: - libbrotlidec=1.1.0=h2466b09_3 - libbrotlienc=1.1.0=h2466b09_3 - libcblas=3.9.0=32_h9bd4c3b_openblas - - libclang13=20.1.7=default_h6e92b77_0 + - libclang13=20.1.8=default_hadf22e1_0 - libcurl=8.14.1=h88aaa65_0 - libdeflate=1.24=h76ddb4d_0 - - libexpat=2.7.0=he0c23c2_0 + - libexpat=2.7.1=hac47afa_0 - libffi=3.4.6=h537db12_1 - libflang=19.1.7=he0c23c2_0 - libflint=3.2.2=h4de658f_0 @@ -157,18 +165,18 @@ dependencies: - libopenblas=0.3.30=pthreads_ha4fe6b2_0 - libpng=1.6.50=h95bef1e_0 - libsodium=1.0.20=hc70643c_0 - - libsqlite=3.50.2=hf5d6505_0 + - libsqlite=3.50.3=hf5d6505_1 - libssh2=1.11.1=h9aa295b_0 - libstdcxx=15.1.0=h904f734_3 - libstdcxx-devel_win-64=15.1.0=hec057c1_103 - libtiff=4.7.0=h05922d8_5 - - libwebp-base=1.5.0=h3b0e114_0 + - libwebp-base=1.6.0=h4d5522a_0 - libwinpthread=12.0.0.r4.gg4f2fc60ca=h57928b3_9 - libxcb=1.17.0=h0e4246c_0 - libxml2=2.13.8=h442d1da_0 - - libxslt=1.1.39=h3df6e99_0 + - libxslt=1.1.43=h25c3957_0 - libzlib=1.3.1=h2466b09_2 - - lld=20.1.7=he99c172_0 + - lld=20.1.8=h5383324_0 - llvm-tools=19.1.7=h2a44499_1 - m2w64-sysroot_win-64=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 - m4ri=20240729=h4afdad8_1 @@ -184,6 +192,7 @@ dependencies: - mingw-w64-ucrt-x86_64-headers-git=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 - mingw-w64-ucrt-x86_64-windows-default-manifest=6.4=he206cdd_7 - mingw-w64-ucrt-x86_64-winpthreads-git=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h72bc38f_1 - mpfr=4.2.1=hbc20e70_3 @@ -191,14 +200,21 @@ dependencies: - msgpack-python=1.1.1=py311h3257749_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.6.11=h2fa13f4_1 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h79cd779_0 - - numpy=2.3.1=py311haedcf98_0 + - ninja=1.13.1=h477610d_0 + - numpy=2.3.1=py311h80b3fa1_1 - openblas=0.3.30=pthreads_h4a7f399_0 - openjpeg=2.5.3=h4d64b90_0 - openssl=3.5.1=h725018a_0 - packaging=25.0=pyh29332c3_1 + - pandoc=3.7.0.2=h57928b3_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pari=2.17.2=h7f476ce_4_single - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 @@ -211,7 +227,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py311h0f9b5fc_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=had0cd8c_0 + - pixman=0.46.4=hc614b68_0 - pkg-config=0.29.2=h88c491f_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -249,25 +265,27 @@ dependencies: - python-installer=0.7.0=pyhff2d567_1 - python-symengine=0.14.0=py311h17a871d_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.11=7_cp311 + - python_abi=3.11=8_cp311 - pytz=2025.2=pyhd8ed1ab_0 - - pywin32=307=py311hda3d55a_3 + - pywin32=311=py311hefeebc8_0 - pywin32-ctypes=0.2.3=py311h1ea47a8_1 - pyyaml=6.0.2=py311h5082efb_2 - pyzmq=27.0.0=py311h484c95c_0 - qhull=2020.2=hc790b64_5 - - qt6-main=6.9.1=h02ddd7d_1 + - qt6-main=6.9.1=h02ddd7d_2 - r-base=4.4.3=h80eeea9_2 - r-lattice=0.22_7=r44h11b023d_0 - rapidfuzz=3.13.0=py311hda3d55a_0 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py311hf51aa87_0 - ruamel.yaml=0.18.14=py311he736701_0 - ruamel.yaml.clib=0.2.8=py311he736701_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=hd40eec1_0 + - ruff=0.12.4=hd40eec1_0 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 @@ -275,7 +293,7 @@ dependencies: - semver=3.0.4=pyhd8ed1ab_0 - setuptools=80.9.0=pyhff2d567_0 - shellingham=1.5.4=pyhd8ed1ab_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -289,12 +307,13 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hdb435a2_0 + - sqlite=3.50.3=hdb435a2_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h1ba984b_1 - symmetrica=3.0.1=h1537add_0 - sympy=1.14.0=pyh04b8f61_5 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=h2c6b04d_2 - tktable=2.10=h7e9e0db_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -312,14 +331,15 @@ dependencies: - ucrt=10.0.22621.0=h57928b3_1 - unicodedata2=16.0.0=py311he736701_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h579f82e_0 - - vc=14.3=h41ae7f8_26 - - vc14_runtime=14.44.35208=h818238b_26 - - virtualenv=20.31.2=pyhd8ed1ab_0 - - vs2015_runtime=14.44.35208=h38c0c73_26 - - vs2022_win-64=19.44.35207=ha74f236_26 + - uv=0.8.2=h579f82e_0 + - vc=14.3=h2b53caa_30 + - vc14_runtime=14.44.35208=h818238b_30 + - virtualenv=20.32.0=pyhd8ed1ab_0 + - vs2015_runtime=14.44.35208=h38c0c73_30 + - vs2022_win-64=19.44.35207=ha74f236_30 - vswhere=3.1.7=h40126e0_1 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - win_inet_pton=1.1.0=pyh7428d3b_8 diff --git a/environment-3.12-linux-aarch64.yml b/environment-3.12-linux-aarch64.yml index 83ab2acb322..4a0c5172e1a 100644 --- a/environment-3.12-linux-aarch64.yml +++ b/environment-3.12-linux-aarch64.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: linux-aarch64 -# input_hash: fdb7d62e115b67b85c56fce1ed0224ddb918bea07e016e3c7237cbb8b1c6842f +# input_hash: a3b8e7563aab0e446b6094c9a9b933bc1d458ef6bcb451dbbe9e74a8b5b761c7 channels: - conda-forge @@ -14,6 +14,7 @@ dependencies: - appdirs=1.4.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_h6fc4d3a_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321hbecfd40_1 - automake=1.17=pl5321h8af1aa0_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -21,11 +22,13 @@ dependencies: - backports.tarfile=1.2.0=pyhd8ed1ab_1 - bdw-gc=8.2.8=h5ad3122_2 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils=2.44=hf1166c9_0 - - binutils_impl_linux-aarch64=2.44=h4c662bb_0 - - binutils_linux-aarch64=2.44=hf1166c9_0 + - binutils=2.44=hf1166c9_1 + - binutils_impl_linux-aarch64=2.44=h4c662bb_1 + - binutils_linux-aarch64=2.44=hf1166c9_1 - blas=2.132=openblas - blas-devel=3.9.0=32_h9678261_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h2a328a1_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=hdad291f_4 @@ -37,12 +40,12 @@ dependencies: - bzip2=1.0.8=h68df207_7 - c-ares=1.34.5=h86ecc28_0 - c-compiler=1.10.0=h6561dab_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h83712da_0 - cddlib=1!0.94m=h719063d_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py312hac81daf_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - click=8.2.1=pyh707e725_0 @@ -66,10 +69,11 @@ dependencies: - cysignals=1.12.3=py312h6f74592_0 - cython=3.1.2=py312hb75641d_2 - dbus=1.13.6=h12b9eeb_3 - - debugpy=1.8.14=py312h6f74592_0 + - debugpy=1.8.15=py312hf55c4e8_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=h5ad3122_0 - dulwich=0.22.8=py312h8cbf658_0 @@ -80,7 +84,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h5ad3122_0 + - expat=2.7.1=hfae3067_0 - fflas-ffpack=2.5.0=h503e619_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -92,7 +96,7 @@ dependencies: - fontconfig=2.15.0=h8dda3cd_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py312hcc812fe_0 + - fonttools=4.59.0=py312ha4530ae_0 - fortran-compiler=1.10.0=h25a59a9_0 - fplll=5.5.0=h45c7457_0 - fpylll=0.6.3=py312h37c3976_0 @@ -139,21 +143,25 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jeepney=0.9.0=pyhd8ed1ab_0 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h05a177a_18 + - kernel-headers_linux-aarch64=4.18.0=h05a177a_8 - keyring=25.6.0=pyha804496_0 - keyutils=1.6.1=h4e544f5_0 - kiwisolver=1.4.8=py312h88dc405_1 - krb5=1.21.3=h50a48e9_0 - lcalc=2.1.0=h30a6b3d_1 - lcms2=2.17=hc88f144_0 - - ld_impl_linux-aarch64=2.44=h5e2c951_0 + - ld_impl_linux-aarch64=2.44=h5e2c951_1 - lerc=4.0.0=hfdc4d58_1 - libblas=3.9.0=32_h1a9f1db_openblas - libboost=1.85.0=h9fa81b4_4 @@ -165,8 +173,8 @@ dependencies: - libbrotlidec=1.1.0=h86ecc28_3 - libbrotlienc=1.1.0=h86ecc28_3 - libcblas=3.9.0=32_hab92f65_openblas - - libclang-cpp20.1=20.1.7=default_h7d4303a_0 - - libclang13=20.1.7=default_h9e36cb9_0 + - libclang-cpp20.1=20.1.8=default_hf07bfb7_0 + - libclang13=20.1.8=default_h173080d_0 - libcups=2.3.3=h5cdc715_5 - libcurl=8.14.1=h6702fde_0 - libdeflate=1.24=he377734_0 @@ -174,7 +182,7 @@ dependencies: - libedit=3.1.20250104=pl5321h976ea20_0 - libegl=1.7.0=hd24410f_2 - libev=4.33=h31becfc_2 - - libexpat=2.7.0=h5ad3122_0 + - libexpat=2.7.1=hfae3067_0 - libffi=3.4.6=he21f813_1 - libflint=3.2.2=hd878b8d_0 - libfreetype=2.13.3=h8af1aa0_1 @@ -196,7 +204,7 @@ dependencies: - libjpeg-turbo=3.1.0=h86ecc28_0 - liblapack=3.9.0=32_h411afd4_openblas - liblapacke=3.9.0=32_hc659ca5_openblas - - libllvm20=20.1.7=h07bd352_0 + - libllvm20=20.1.8=h2b567e5_0 - liblzma=5.8.1=h86ecc28_2 - liblzma-devel=5.8.1=h86ecc28_2 - libnghttp2=1.64.0=hc8609a4_0 @@ -209,19 +217,19 @@ dependencies: - libpq=17.5=hf590da8_0 - libsanitizer=13.3.0=ha58e236_2 - libsodium=1.0.20=h68df207_0 - - libsqlite=3.50.2=he2a92bd_0 + - libsqlite=3.50.3=h022381a_1 - libssh2=1.11.1=h18c354c_0 - libstdcxx=15.1.0=h3f4de04_3 - libstdcxx-devel_linux-aarch64=13.3.0=h0c07274_102 - libstdcxx-ng=15.1.0=hf1166c9_3 - libtiff=4.7.0=h7c15681_5 - libuuid=2.38.1=hb4cce97_0 - - libwebp-base=1.5.0=h0886dbf_0 + - libwebp-base=1.6.0=ha2e29f5_0 - libxcb=1.17.0=h262b8f6_0 - libxcrypt=4.4.36=h31becfc_1 - libxkbcommon=1.10.0=hbab7b08_0 - libxml2=2.13.8=he060846_0 - - libxslt=1.1.39=h1cc9640_0 + - libxslt=1.1.43=h4552c8e_0 - libzlib=1.3.1=h86ecc28_2 - linbox=1.7.0=h8d1c19e_2 - lrcalc=2.1=h5ad3122_7 @@ -238,6 +246,7 @@ dependencies: - memory-allocator=0.1.3=py312hb2c0f52_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h783934e_1 - mpfi=1.5.4=h846f343_1001 @@ -246,18 +255,25 @@ dependencies: - msgpack-python=1.1.1=py312h451a7dd_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=h86ecc28_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=ha32ae93_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=ha6136e2_0 + - ninja=1.13.1=hdc560ac_0 - ntl=11.4.3=h0d7519b_1 - - numpy=2.3.1=py312h1fd0f8e_0 + - numpy=2.3.1=py312h6615c27_1 - openblas=0.3.30=pthreads_h3a8cbd8_0 - openjpeg=2.5.3=h3f56577_0 - openldap=2.6.10=h30c48ee_0 - openssl=3.5.1=hd08dc88_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=hb9de7d4_0 + - pandoc=3.7.0.2=h8af1aa0_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.3=h1e6a6fd_1 - pari=2.17.2=h45cace7_4_pthread - pari-elldata=0.0.20161017=0 @@ -271,7 +287,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py312h719f0cf_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h86a87f0_0 + - pixman=0.46.4=h3945e86_0 - pkg-config=0.29.2=hce167ba_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -314,7 +330,7 @@ dependencies: - python-lrcalc=2.1=py312h6f74592_7 - python-symengine=0.14.0=py312h70ee296_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.12=7_cp312 + - python_abi=3.12=8_cp312 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py312hcc812fe_2 - pyzmq=27.0.0=py312h2427ae1_0 @@ -325,15 +341,17 @@ dependencies: - r-lattice=0.22_6=r42h25e906a_0 - rapidfuzz=3.13.0=py312h6f74592_0 - readline=8.2=h8382b9d_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py312hf05e714_0 - rpy2=3.5.11=py312r42h3e17d05_3 - ruamel.yaml=0.18.14=py312hb2c0f52_0 - ruamel.yaml.clib=0.2.8=py312hb2c0f52_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=h4384887_0 + - ruff=0.12.4=ha8c5b7e_0 - rw=0.9=h31becfc_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -347,7 +365,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=hfdb71ee_1 - sirocco=2.1.0=h7fa4f89_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -361,15 +379,16 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=h1b15455_0 + - sqlite=3.50.3=he8854b5_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h7a35ef0_1 - symmetrica=3.0.1=hd600fc2_0 - sympow=2.023.6=h4d450c3_4 - sympy=1.14.0=pyh2585a3b_105 - - sysroot_linux-aarch64=2.17=h68829e0_18 + - sysroot_linux-aarch64=2.28=h585391f_8 - tachyon=0.99b6=ha0bfc61_1002 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=noxft_h5688188_102 - tktable=2.10=h89546af_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -387,10 +406,11 @@ dependencies: - tzlocal=5.3=py312h996f985_0 - unicodedata2=16.0.0=py312hb2c0f52_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h607dc9b_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=hc9499e0_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wayland=1.24.0=h698ed42_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py312hb2c0f52_0 diff --git a/environment-3.12-linux.yml b/environment-3.12-linux.yml index 35331bec05d..d6145b8118e 100644 --- a/environment-3.12-linux.yml +++ b/environment-3.12-linux.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: linux-64 -# input_hash: e6dce4824b75fda72cf7f2291e0f3773e750cc53c0e18bcdb2b63b6c6e471534 +# input_hash: a17f8b861d2ec845678853af158e3c9f4119c1ad2b906aa916157bd81509ce39 channels: - conda-forge @@ -16,6 +16,7 @@ dependencies: - appdirs=1.4.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_hf03ea27_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321hbb4ee43_1 - automake=1.17=pl5321ha770c72_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -23,11 +24,13 @@ dependencies: - backports.tarfile=1.2.0=pyhd8ed1ab_1 - bdw-gc=8.2.8=h5888daf_2 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils=2.44=h4852527_0 - - binutils_impl_linux-64=2.44=h4bf12b8_0 - - binutils_linux-64=2.44=h4852527_0 + - binutils=2.44=h4852527_1 + - binutils_impl_linux-64=2.44=h4bf12b8_1 + - binutils_linux-64=2.44=h4852527_1 - blas=2.132=openblas - blas-devel=3.9.0=32_h1ea3ea9_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h00ab1b0_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=h3c6214e_4 @@ -39,12 +42,12 @@ dependencies: - bzip2=1.0.8=h4bc722e_7 - c-ares=1.34.5=hb9d3cd8_0 - c-compiler=1.10.0=h2b85faf_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h3394656_0 - cddlib=1!0.94m=h9202a9a_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py312h06ac9bb_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - click=8.2.1=pyh707e725_0 @@ -68,10 +71,11 @@ dependencies: - cysignals=1.12.3=py312h2ec8cdc_0 - cython=3.1.2=py312h2614dfc_2 - dbus=1.16.2=h3c4dab8_0 - - debugpy=1.8.14=py312h2ec8cdc_0 + - debugpy=1.8.15=py312h8285ef7_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=h5888daf_0 - dulwich=0.22.8=py312h12e396e_0 @@ -82,7 +86,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h5888daf_0 + - expat=2.7.1=hecca717_0 - fflas-ffpack=2.5.0=h4f9960b_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -94,7 +98,7 @@ dependencies: - fontconfig=2.15.0=h7e30c49_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py312h178313f_0 + - fonttools=4.59.0=py312h8a5da7c_0 - fortran-compiler=1.10.0=h36df796_0 - fplll=5.5.0=hd20a173_0 - fpylll=0.6.3=py312ha4ee43a_0 @@ -124,7 +128,7 @@ dependencies: - gxx_impl_linux-64=13.3.0=hae580e1_2 - gxx_linux-64=13.3.0=hb14504d_11 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=h3beb420_0 + - harfbuzz=11.3.2=hbb57e21_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he02047a_0 @@ -141,21 +145,25 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jeepney=0.9.0=pyhd8ed1ab_0 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - - kernel-headers_linux-64=3.10.0=he073ed8_18 + - kernel-headers_linux-64=4.18.0=he073ed8_8 - keyring=25.6.0=pyha804496_0 - keyutils=1.6.1=h166bdaf_0 - kiwisolver=1.4.8=py312h68727a3_1 - krb5=1.21.3=h659f571_0 - lcalc=2.1.0=h9cf73fc_1 - lcms2=2.17=h717163a_0 - - ld_impl_linux-64=2.44=h1423503_0 + - ld_impl_linux-64=2.44=h1423503_1 - lerc=4.0.0=h0aef613_1 - libblas=3.9.0=32_h59b9bed_openblas - libboost=1.85.0=h0ccab89_4 @@ -167,8 +175,8 @@ dependencies: - libbrotlidec=1.1.0=hb9d3cd8_3 - libbrotlienc=1.1.0=hb9d3cd8_3 - libcblas=3.9.0=32_he106b2a_openblas - - libclang-cpp20.1=20.1.7=default_h1df26ce_0 - - libclang13=20.1.7=default_he06ed0a_0 + - libclang-cpp20.1=20.1.8=default_hddf928d_0 + - libclang13=20.1.8=default_ha444ac7_0 - libcups=2.3.3=hb8b1518_5 - libcurl=8.14.1=h332b0f4_0 - libdeflate=1.24=h86f0d12_0 @@ -176,7 +184,7 @@ dependencies: - libedit=3.1.20250104=pl5321h7949ede_0 - libegl=1.7.0=ha4b6fd6_2 - libev=4.33=hd590300_2 - - libexpat=2.7.0=h5888daf_0 + - libexpat=2.7.1=hecca717_0 - libffi=3.4.6=h2dba641_1 - libflint=3.2.2=h754cb6e_0 - libfreetype=2.13.3=ha770c72_1 @@ -198,7 +206,7 @@ dependencies: - libjpeg-turbo=3.1.0=hb9d3cd8_0 - liblapack=3.9.0=32_h7ac8fdf_openblas - liblapacke=3.9.0=32_he2f377e_openblas - - libllvm20=20.1.7=he9d0ab4_0 + - libllvm20=20.1.8=hecd9e04_0 - liblzma=5.8.1=hb9d3cd8_2 - liblzma-devel=5.8.1=hb9d3cd8_2 - libnghttp2=1.64.0=h161d5f1_0 @@ -211,19 +219,19 @@ dependencies: - libpq=17.5=h27ae623_0 - libsanitizer=13.3.0=he8ea267_2 - libsodium=1.0.20=h4ab18f5_0 - - libsqlite=3.50.2=h6cd9bfd_0 + - libsqlite=3.50.3=hee844dc_1 - libssh2=1.11.1=hcf80075_0 - libstdcxx=15.1.0=h8f9b012_3 - libstdcxx-devel_linux-64=13.3.0=hc03c837_102 - libstdcxx-ng=15.1.0=h4852527_3 - libtiff=4.7.0=hf01ce69_5 - libuuid=2.38.1=h0b41bf4_0 - - libwebp-base=1.5.0=h851e524_0 + - libwebp-base=1.6.0=hd42ef1d_0 - libxcb=1.17.0=h8a09558_0 - libxcrypt=4.4.36=hd590300_1 - libxkbcommon=1.10.0=h65c71a3_0 - libxml2=2.13.8=h4bc477f_0 - - libxslt=1.1.39=h76b75d6_0 + - libxslt=1.1.43=h7a3aeb2_0 - libzlib=1.3.1=hb9d3cd8_2 - linbox=1.7.0=h0451620_2 - lrcalc=2.1=h5888daf_7 @@ -241,6 +249,7 @@ dependencies: - memory-allocator=0.1.3=py312h66e93f0_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h24ddda3_1 - mpfi=1.5.4=h9f54685_1001 @@ -249,18 +258,25 @@ dependencies: - msgpack-python=1.1.1=py312h68727a3_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=hb9d3cd8_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=h2d0b736_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h7aa8ee6_0 + - ninja=1.13.1=h171cf75_0 - ntl=11.4.3=hef3c4d3_1 - - numpy=2.3.1=py312h6cf2f7f_0 + - numpy=2.3.1=py312h33ff503_1 - openblas=0.3.30=pthreads_h6ec200e_0 - openjpeg=2.5.3=h5fbd93e_0 - openldap=2.6.10=he970967_0 - openssl=3.5.1=h7b32b05_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=h36c2ea0_0 + - pandoc=3.7.0.2=ha770c72_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.4=hadf4263_0 - pari=2.17.2=ha40142e_4_pthread - pari-elldata=0.0.20161017=0 @@ -274,7 +290,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py312h80c1187_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h29eaf8c_0 + - pixman=0.46.4=h537e5f6_0 - pkg-config=0.29.2=h4bc722e_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -317,7 +333,7 @@ dependencies: - python-lrcalc=2.1=py312h2ec8cdc_7 - python-symengine=0.14.0=py312h406a2a9_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.12=7_cp312 + - python_abi=3.12=8_cp312 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py312h178313f_2 - pyzmq=27.0.0=py312hbf22597_0 @@ -328,15 +344,17 @@ dependencies: - r-lattice=0.22_6=r42h57805ef_0 - rapidfuzz=3.13.0=py312h2ec8cdc_0 - readline=8.2=h8c095d6_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py312h680f630_0 - rpy2=3.5.11=py312r42hc7c0aa3_3 - ruamel.yaml=0.18.14=py312h66e93f0_0 - ruamel.yaml.clib=0.2.8=py312h66e93f0_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=hcc1af86_0 + - ruff=0.12.4=hf9daec2_0 - rw=0.9=hd590300_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -350,7 +368,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=h7ee4ccf_1 - sirocco=2.1.0=hd7ee782_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -364,15 +382,16 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hb7a22d2_0 + - sqlite=3.50.3=heff268d_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h064106a_1 - symmetrica=3.0.1=hcb278e6_0 - sympow=2.023.6=h3028977_4 - sympy=1.14.0=pyh2585a3b_105 - - sysroot_linux-64=2.17=h0157908_18 + - sysroot_linux-64=2.28=h4ee821c_8 - tachyon=0.99b6=hba7d16a_1002 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=noxft_hd72426e_102 - tktable=2.10=h8d826fa_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -390,10 +409,11 @@ dependencies: - tzlocal=5.3=py312h7900ff3_0 - unicodedata2=16.0.0=py312h66e93f0_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h29fcd0c_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=heb9285d_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wayland=1.24.0=h3e06ad9_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py312h66e93f0_0 diff --git a/environment-3.12-macos-x86_64.yml b/environment-3.12-macos-x86_64.yml index dee222b5548..61bf13d4a53 100644 --- a/environment-3.12-macos-x86_64.yml +++ b/environment-3.12-macos-x86_64.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: osx-64 -# input_hash: 46eae750e88393469f4cd3b3db35f6db6c61cfb4575535389d70195fc4c84b9c +# input_hash: 3b8b622f55d398018a1761788b66353659c11ab769f56e6f3abdf56e092eb42a channels: - conda-forge @@ -14,6 +14,7 @@ dependencies: - appnope=0.1.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_hdfe9103_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321had7229c_1 - automake=1.17=pl5321h694c41f_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -23,6 +24,8 @@ dependencies: - beautifulsoup4=4.13.4=pyha770c72_0 - blas=2.132=openblas - blas-devel=3.9.0=32_hbf4f893_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h7728843_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=hfcd56d9_4 @@ -33,31 +36,31 @@ dependencies: - bwidget=1.10.1=h694c41f_1 - bzip2=1.0.8=hfdf4475_7 - c-ares=1.34.5=hf13058a_0 - - c-compiler=1.10.0=h09a7c41_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - c-compiler=1.11.0=h7a00415_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h950ec3b_0 - - cctools=1010.6=ha66f10e_6 - - cctools_osx-64=1010.6=hd19c6af_6 + - cctools=1021.4=h67a6458_1 + - cctools_osx-64=1021.4=haa85c18_1 - cddlib=1!0.94m=h0f52abe_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py312hf857d28_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - - clang=18.1.8=default_h576c50e_10 - - clang-18=18.1.8=default_h3571c67_10 - - clang_impl_osx-64=18.1.8=h6a44ed1_25 - - clang_osx-64=18.1.8=h7e5c614_25 - - clangxx=18.1.8=default_heb2e8d1_10 - - clangxx_impl_osx-64=18.1.8=h4b7810f_25 - - clangxx_osx-64=18.1.8=h7e5c614_25 + - clang=19.1.7=default_h576c50e_3 + - clang-19=19.1.7=default_h3571c67_3 + - clang_impl_osx-64=19.1.7=hc73cdc9_25 + - clang_osx-64=19.1.7=h7e5c614_25 + - clangxx=19.1.7=default_heb2e8d1_3 + - clangxx_impl_osx-64=19.1.7=hb295874_25 + - clangxx_osx-64=19.1.7=h7e5c614_25 - click=8.2.1=pyh707e725_0 - click-default-group=1.2.4=pyhd8ed1ab_1 - cliquer=1.22=h10d778d_1 - colorama=0.4.6=pyhd8ed1ab_1 - comm=0.2.2=pyhd8ed1ab_1 - - compiler-rt=18.1.8=h1020d70_1 - - compiler-rt_osx-64=18.1.8=hf2b8a54_1 + - compiler-rt=19.1.7=h52031e2_0 + - compiler-rt_osx-64=19.1.7=hc6f8467_0 - conda-lock=3.0.4=pyhb3ed7dc_1 - conda-souschef=2.2.3=pyhd8ed1ab_0 - contourpy=1.3.2=py312hc47a885_0 @@ -67,15 +70,16 @@ dependencies: - crashtest=0.4.1=pyhd8ed1ab_1 - cryptography=45.0.5=py312h0995e51_0 - curl=8.14.1=h5dec5d8_0 - - cxx-compiler=1.10.0=h20888b2_0 + - cxx-compiler=1.11.0=h307afc9_0 - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.2.2=py312hcedb801_0 - cysignals=1.12.3=py312haafddd8_0 - cython=3.1.2=py312hdfbeeba_2 - - debugpy=1.8.14=py312haafddd8_0 + - debugpy=1.8.15=py312h2ac44ba_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - dulwich=0.22.8=py312h0d0de52_0 - ecl=24.5.10=ha6bf567_1 @@ -85,7 +89,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h240833e_0 + - expat=2.7.1=h21dd04a_0 - fflas-ffpack=2.5.0=h5898d61_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -97,7 +101,7 @@ dependencies: - fontconfig=2.15.0=h37eeddb_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py312h3520af0_0 + - fonttools=4.59.0=py312h3d55d04_0 - fortran-compiler=1.10.0=h02557f8_0 - fplll=5.5.0=h6ede486_0 - fpylll=0.6.3=py312hfffdf69_0 @@ -108,9 +112,9 @@ dependencies: - gap-defaults=4.14.0=h694c41f_5 - gf2x=1.3.0=h35ac7d9_3 - gfan=0.6.2=hd793b56_1003 - - gfortran=13.3.0=hcc3c99d_1 - - gfortran_impl_osx-64=13.3.0=hbf5bf67_105 - - gfortran_osx-64=13.3.0=h3223c34_1 + - gfortran=13.4.0=hcc3c99d_0 + - gfortran_impl_osx-64=13.4.0=h8d0df8b_0 + - gfortran_osx-64=13.4.0=h3223c34_0 - gitdb=4.0.12=pyhd8ed1ab_0 - gitpython=3.1.44=pyhff2d567_0 - givaro=4.2.0=h89f8175_2 @@ -121,7 +125,7 @@ dependencies: - grayskull=2.9.1=pyhd8ed1ab_0 - gsl=2.8=hc707ee6_1 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=hdfbcdba_0 + - harfbuzz=11.3.2=hb258ee5_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=h120a0e1_0 @@ -139,21 +143,25 @@ dependencies: - isl=0.26=imath32_h2e86a7b_101 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh534df25_0 - kiwisolver=1.4.8=py312hc47a885_1 - krb5=1.21.3=h37d8d59_0 - lcalc=2.1.0=h0f747f7_1 - lcms2=2.17=h72f5680_0 - - ld64=951.9=h4e51db5_6 - - ld64_osx-64=951.9=h33512f0_6 + - ld64=954.16=hc3792c1_1 + - ld64_osx-64=954.16=hf1c22e8_1 - lerc=4.0.0=hcca01a6_1 - - libasprintf=0.25.1=h27064b9_0 + - libasprintf=0.25.1=h3184127_1 - libblas=3.9.0=32_h7f60823_openblas - libboost=1.85.0=hcca3243_4 - libboost-devel=1.85.0=h2b186f8_4 @@ -164,48 +172,48 @@ dependencies: - libbrotlidec=1.1.0=h6e16a3a_3 - libbrotlienc=1.1.0=h6e16a3a_3 - libcblas=3.9.0=32_hff6cab4_openblas - - libclang-cpp18.1=18.1.8=default_h3571c67_10 + - libclang-cpp19.1=19.1.7=default_h3571c67_3 - libcurl=8.14.1=h5dec5d8_0 - - libcxx=20.1.7=hf95d169_0 - - libcxx-devel=18.1.8=h7c275be_8 + - libcxx=20.1.8=h3d58e20_1 + - libcxx-devel=19.1.7=h7c275be_1 - libdeflate=1.24=hcc1b750_0 - libedit=3.1.20250104=pl5321ha958ccf_0 - libev=4.33=h10d778d_2 - - libexpat=2.7.0=h240833e_0 + - libexpat=2.7.1=h21dd04a_0 - libffi=3.4.6=h281671d_1 - libflint=3.2.2=h26b1ecd_0 - libfreetype=2.13.3=h694c41f_1 - libfreetype6=2.13.3=h40dfd5c_1 - libgd=2.3.3=h8555400_11 - - libgettextpo=0.25.1=h27064b9_0 + - libgettextpo=0.25.1=h3184127_1 - libgfortran=5.0.0=14_2_0_h51e75f0_103 - - libgfortran-devel_osx-64=13.3.0=h297be85_105 + - libgfortran-devel_osx-64=13.4.0=hbfa0f67_0 - libgfortran5=14.2.0=h51e75f0_103 - libglib=2.84.2=h3139dbc_0 - libhomfly=1.02r6=h10d778d_1 - libiconv=1.18=h4b5e92a_1 - - libintl=0.25.1=h27064b9_0 + - libintl=0.25.1=h3184127_1 - libjpeg-turbo=3.1.0=h6e16a3a_0 - liblapack=3.9.0=32_h236ab99_openblas - liblapacke=3.9.0=32_h85686d2_openblas - - libllvm18=18.1.8=hc29ff6c_3 + - libllvm19=19.1.7=hc29ff6c_1 - liblzma=5.8.1=hd471939_2 - liblzma-devel=5.8.1=hd471939_2 - libnghttp2=1.64.0=hc7306c3_0 - libopenblas=0.3.30=openmp_hbf64a52_0 - libpng=1.6.50=h3c4a55f_0 - libsodium=1.0.20=hfdf4475_0 - - libsqlite=3.50.2=he7d56d0_0 + - libsqlite=3.50.3=h875aaf5_1 - libssh2=1.11.1=hed3591d_0 - libtiff=4.7.0=h1167cee_5 - - libwebp-base=1.5.0=h6cf52b4_0 + - libwebp-base=1.6.0=hb807250_0 - libxcb=1.17.0=hf1f96e2_0 - libxml2=2.13.8=h93c44a6_0 - libzlib=1.3.1=hd23fc13_2 - linbox=1.7.0=h1e49b7d_2 - - llvm-openmp=20.1.7=ha54dae1_0 - - llvm-tools=18.1.8=hc29ff6c_3 - - llvm-tools-18=18.1.8=hc29ff6c_3 + - llvm-openmp=20.1.8=hf4e0ed4_0 + - llvm-tools=19.1.7=h3fe3016_1 + - llvm-tools-19=19.1.7=he90a8e3_1 - lrcalc=2.1=hac325c4_7 - lrslib=71.b=hda3377a_1 - m4=1.4.20=h6e16a3a_0 @@ -221,6 +229,7 @@ dependencies: - memory-allocator=0.1.3=py312hb553811_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h9d8efa1_1 - mpfi=1.5.4=h52b28e3_1001 @@ -229,17 +238,24 @@ dependencies: - msgpack-python=1.1.1=py312hc47a885_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=h6e16a3a_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=h0622a9a_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h46ed394_0 + - ninja=1.13.1=h0ba0a54_0 - ntl=11.4.3=h0ab3c2f_1 - - numpy=2.3.1=py312h3b44349_0 + - numpy=2.3.1=py312hda18a35_1 - openblas=0.3.30=openmp_h30af337_0 - openjpeg=2.5.3=h7fd6d84_0 - openssl=3.5.1=hc426f3f_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=hbcb3906_0 + - pandoc=3.7.0.2=h694c41f_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.4=h6ef8af8_0 - pari=2.17.2=h1ed0f1a_4_pthread - pari-elldata=0.0.20161017=0 @@ -253,7 +269,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py312hd9f36e3_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h1fd1274_0 + - pixman=0.46.4=h6f2c7e4_0 - pkg-config=0.29.2=hf7e621a_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -295,7 +311,7 @@ dependencies: - python-lrcalc=2.1=py312h5861a67_7 - python-symengine=0.14.0=py312h33d1391_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.12=7_cp312 + - python_abi=3.12=8_cp312 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py312h3520af0_2 - pyzmq=27.0.0=py312h679dbab_0 @@ -305,15 +321,17 @@ dependencies: - r-lattice=0.22_6=r42hb2c329c_0 - rapidfuzz=3.13.0=py312haafddd8_0 - readline=8.2=h7cca4af_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py312haba3716_0 - rpy2=3.5.11=py312r42h5d6a8aa_3 - ruamel.yaml=0.18.14=py312h01d7ebd_0 - ruamel.yaml.clib=0.2.8=py312h3d0f464_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=h8aa17f0_0 + - ruff=0.12.4=h6cc4cfe_0 - rw=0.9=h10d778d_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -326,7 +344,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=haa275bf_1 - sirocco=2.1.0=hfc2cc1e_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -340,7 +358,7 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=h22fafd5_0 + - sqlite=3.50.3=h8d07200_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h79ccd14_1 @@ -349,6 +367,7 @@ dependencies: - sympy=1.14.0=pyh2585a3b_105 - tachyon=0.99b6=h3a1d103_1002 - tapi=1300.6.5=h390ca13_0 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=hf689a15_2 - tktable=2.10=h2c093e9_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -366,13 +385,14 @@ dependencies: - tzlocal=5.3=py312hb401068_0 - unicodedata2=16.0.0=py312h01d7ebd_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=hb40bb8a_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=hfa71dfd_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py312h01d7ebd_0 - - xattr=1.1.0=py312hb553811_1 + - xattr=1.2.0=py312hff0d1ab_0 - xorg-libxau=1.0.12=h6e16a3a_0 - xorg-libxdmcp=1.1.5=h00291cd_0 - xz=5.8.1=h357f2ed_2 diff --git a/environment-3.12-macos.yml b/environment-3.12-macos.yml index eb1afd0232d..9bd31602c62 100644 --- a/environment-3.12-macos.yml +++ b/environment-3.12-macos.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: osx-arm64 -# input_hash: 3c47d805a182f595cf29a50dad76ca375e9a8ffdfc19293841999e7040b1bfb7 +# input_hash: f77f2945f9feb36d438d449a1eae77c2ece8357607769d90b4aabb5d2663f330 channels: - conda-forge @@ -13,6 +13,7 @@ dependencies: - appnope=0.1.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_h1f29f7c_102 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - autoconf=2.72=pl5321hd3c70e0_1 - automake=1.17=pl5321hce30654_0 - babel=2.17.0=pyhd8ed1ab_0 @@ -22,6 +23,8 @@ dependencies: - beautifulsoup4=4.13.4=pyha770c72_0 - blas=2.132=openblas - blas-devel=3.9.0=32_h11c0a38_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - bliss=0.77=h2ffa867_1 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=h103c1d6_4 @@ -32,22 +35,22 @@ dependencies: - bwidget=1.10.1=hce30654_1 - bzip2=1.0.8=h99b78c6_7 - c-ares=1.34.5=h5505292_0 - - c-compiler=1.10.0=hdf49b6b_0 - - ca-certificates=2025.6.15=hbd8a1cb_0 + - c-compiler=1.9.0=hdf49b6b_0 + - ca-certificates=2025.7.14=hbd8a1cb_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h6a3b0d2_0 - - cctools=1010.6=hb4fb6a3_6 - - cctools_osx-arm64=1010.6=h3b4f5d3_6 + - cctools=1021.4=hb4fb6a3_0 + - cctools_osx-arm64=1021.4=h12580ec_0 - cddlib=1!0.94m=h6d7a090_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py312h0fad829_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - - clang=18.1.8=default_h474c9e2_10 - - clang-18=18.1.8=default_hf90f093_10 + - clang=18.1.8=default_h1eedb11_11 + - clang-18=18.1.8=default_h649e436_11 - clang_impl_osx-arm64=18.1.8=h2ae9ea5_25 - clang_osx-arm64=18.1.8=h07b0088_25 - - clangxx=18.1.8=default_h1ffe849_10 + - clangxx=18.1.8=default_h0dcb199_11 - clangxx_impl_osx-arm64=18.1.8=h555f467_25 - clangxx_osx-arm64=18.1.8=h07b0088_25 - click=8.2.1=pyh707e725_0 @@ -66,15 +69,16 @@ dependencies: - crashtest=0.4.1=pyhd8ed1ab_1 - cryptography=45.0.5=py312hf9bd80e_0 - curl=8.14.1=h73640d1_0 - - cxx-compiler=1.10.0=hba80287_0 + - cxx-compiler=1.9.0=hba80287_0 - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.2.2=py312he7c0534_0 - cysignals=1.12.3=py312hd8f9ff3_0 - cython=3.1.2=py312h02233ea_2 - - debugpy=1.8.14=py312hd8f9ff3_0 + - debugpy=1.8.15=py312he360a15_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - dulwich=0.22.8=py312hcd83bfe_0 - ecl=24.5.10=hc6c598b_1 @@ -84,7 +88,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=h286801f_0 + - expat=2.7.1=hec049ff_0 - fflas-ffpack=2.5.0=h4bc3318_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 @@ -96,7 +100,7 @@ dependencies: - fontconfig=2.15.0=h1383a14_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py312h998013c_0 + - fonttools=4.59.0=py312h6daa0e5_0 - fortran-compiler=1.10.0=h5692697_0 - fplll=5.5.0=h2a2278a_0 - fpylll=0.6.3=py312h03fe13c_0 @@ -120,7 +124,7 @@ dependencies: - grayskull=2.9.1=pyhd8ed1ab_0 - gsl=2.8=h8d0574d_1 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=hab40de2_0 + - harfbuzz=11.3.2=hcb8449c_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=hfee45f7_0 @@ -138,19 +142,23 @@ dependencies: - isl=0.26=imath32_h347afa1_101 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh31011fe_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh534df25_0 - kiwisolver=1.4.8=py312hb23fbb9_1 - krb5=1.21.3=h237132a_0 - lcalc=2.1.0=hdaf6845_1 - lcms2=2.17=h7eeda09_0 - - ld64=951.9=h4c6efb1_6 - - ld64_osx-arm64=951.9=hb6b49e2_6 + - ld64=954.16=h4c6efb1_0 + - ld64_osx-arm64=954.16=h9d5fcb0_0 - lerc=4.0.0=hd64df32_1 - libasprintf=0.25.1=h493aca8_0 - libblas=3.9.0=32_h10e41b3_openblas @@ -163,14 +171,14 @@ dependencies: - libbrotlidec=1.1.0=h5505292_3 - libbrotlienc=1.1.0=h5505292_3 - libcblas=3.9.0=32_hb3479ef_openblas - - libclang-cpp18.1=18.1.8=default_hf90f093_10 + - libclang-cpp18.1=18.1.8=default_h649e436_11 - libcurl=8.14.1=h73640d1_0 - - libcxx=20.1.7=ha82da77_0 + - libcxx=20.1.8=hf598326_1 - libcxx-devel=18.1.8=h6dc3340_8 - libdeflate=1.24=h5773f1b_0 - libedit=3.1.20250104=pl5321hafb1f1b_0 - libev=4.33=h93a5062_2 - - libexpat=2.7.0=h286801f_0 + - libexpat=2.7.1=hec049ff_0 - libffi=3.4.6=h1da3d7d_1 - libflint=3.2.2=hf825d4a_0 - libfreetype=2.13.3=hce30654_1 @@ -187,24 +195,24 @@ dependencies: - libjpeg-turbo=3.1.0=h5505292_0 - liblapack=3.9.0=32_hc9a63f6_openblas - liblapacke=3.9.0=32_hbb7bcf8_openblas - - libllvm18=18.1.8=hc4b4ae8_3 + - libllvm18=18.1.8=default_h3f49643_6 - liblzma=5.8.1=h39f12f2_2 - liblzma-devel=5.8.1=h39f12f2_2 - libnghttp2=1.64.0=h6d7220d_0 - libopenblas=0.3.30=openmp_hf332438_0 - libpng=1.6.50=h3783ad8_0 - libsodium=1.0.20=h99b78c6_0 - - libsqlite=3.50.2=h6fb428d_0 + - libsqlite=3.50.3=h4237e3c_1 - libssh2=1.11.1=h1590b86_0 - libtiff=4.7.0=h2f21f7c_5 - - libwebp-base=1.5.0=h2471fea_0 + - libwebp-base=1.6.0=h07db88b_0 - libxcb=1.17.0=hdb1d25a_0 - libxml2=2.13.8=h52572c6_0 - libzlib=1.3.1=h8359307_2 - linbox=1.7.0=h66f06df_2 - - llvm-openmp=20.1.7=hdb05f8b_0 - - llvm-tools=18.1.8=hc4b4ae8_3 - - llvm-tools-18=18.1.8=hc4b4ae8_3 + - llvm-openmp=20.1.8=hbb9b287_0 + - llvm-tools=18.1.8=default_h3f49643_6 + - llvm-tools-18=18.1.8=default_h3f49643_6 - lrcalc=2.1=hf9b8971_7 - m4=1.4.20=h5505292_0 - m4ri=20140914=hc97c1ff_1006 @@ -219,6 +227,7 @@ dependencies: - memory-allocator=0.1.3=py312h024a12e_1 - meson=1.8.2=pyhe01879c_0 - meson-python=0.18.0=pyh70fd9c4_0 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h8f1351a_1 - mpfi=1.5.4=hbde5f5b_1001 @@ -227,17 +236,24 @@ dependencies: - msgpack-python=1.1.1=py312hb23fbb9_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.8.9=h5505292_0 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - ncurses=6.5=h5e97a16_3 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=ha024513_0 + - ninja=1.13.1=h4f10f1e_0 - ntl=11.4.3=hbb3f309_1 - - numpy=2.3.1=py312h113b91d_0 + - numpy=2.3.1=py312h2f38b44_1 - openblas=0.3.30=openmp_hea878ba_0 - openjpeg=2.5.3=h8a3d83b_0 - openssl=3.5.1=h81ee809_0 - packaging=25.0=pyh29332c3_1 - palp=2.20=h27ca646_0 + - pandoc=3.7.0.2=hce30654_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pango=1.56.4=h875632e_0 - pari=2.17.2=h49d18c7_4_pthread - pari-elldata=0.0.20161017=0 @@ -251,7 +267,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py312h50aef2c_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=h2f9eb0b_0 + - pixman=0.46.4=h2c80e29_0 - pkg-config=0.29.2=hde07d2e_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -293,7 +309,7 @@ dependencies: - python-lrcalc=2.1=py312hde4cb15_7 - python-symengine=0.14.0=py312hb005d12_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.12=7_cp312 + - python_abi=3.12=8_cp312 - pytz=2025.2=pyhd8ed1ab_0 - pyyaml=6.0.2=py312h998013c_2 - pyzmq=27.0.0=py312hf4875e0_0 @@ -303,15 +319,17 @@ dependencies: - r-lattice=0.22_6=r42hd2d937b_0 - rapidfuzz=3.13.0=py312hd8f9ff3_0 - readline=8.2=h1d1bf99_2 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py312hd3c0895_0 - rpy2=3.5.11=py312r42h3339331_3 - ruamel.yaml=0.18.14=py312hea69d52_0 - ruamel.yaml.clib=0.2.8=py312h0bf5046_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=h412e174_0 + - ruff=0.12.4=h575f11b_0 - rw=0.9=h93a5062_2 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 @@ -324,7 +342,7 @@ dependencies: - simplegeneric=0.8.1=pyhd8ed1ab_2 - singular=4.4.1=h837545d_1 - sirocco=2.1.0=h41f8169_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -338,7 +356,7 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hc23dd5f_0 + - sqlite=3.50.3=hb5dd463_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=hddbed1c_1 @@ -347,6 +365,7 @@ dependencies: - sympy=1.14.0=pyh2585a3b_105 - tachyon=0.99b6=hb8a568e_1002 - tapi=1300.6.5=h03f4b80_0 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=h892fb3f_2 - tktable=2.10=h3c7de25_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -364,13 +383,14 @@ dependencies: - tzlocal=5.3=py312h81bd7bf_0 - unicodedata2=16.0.0=py312hea69d52_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=hcff7401_0 - - virtualenv=20.31.2=pyhd8ed1ab_0 + - uv=0.8.2=hb521335_0 + - virtualenv=20.32.0=pyhd8ed1ab_0 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - wrapt=1.17.2=py312hea69d52_0 - - xattr=1.1.0=py312h024a12e_1 + - xattr=1.2.0=py312h10e72bf_0 - xorg-libxau=1.0.12=h5505292_0 - xorg-libxdmcp=1.1.5=hd74edd7_0 - xz=5.8.1=h9a6d368_2 diff --git a/environment-3.12-win.yml b/environment-3.12-win.yml index 37780eabe2d..017c29372fc 100644 --- a/environment-3.12-win.yml +++ b/environment-3.12-win.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: win-64 -# input_hash: f626cf092384e0f7bdf54799e57f9a7c6ec862a45a6b9d84cb47a3bc269fb619 +# input_hash: edb280af395b699e92c32a65962c605817519a2e64571f7222d56204d419172a channels: - conda-forge @@ -12,13 +12,16 @@ dependencies: - annotated-types=0.7.0=pyhd8ed1ab_1 - appdirs=1.4.4=pyhd8ed1ab_1 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - babel=2.17.0=pyhd8ed1ab_0 - backports=1.0=pyhd8ed1ab_5 - backports.tarfile=1.2.0=pyhd8ed1ab_1 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils_impl_win-64=2.44=h095e170_0 + - binutils_impl_win-64=2.44=h095e170_1 - blas=2.132=openblas - blas-devel=3.9.0=32_hc0f8095_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=ha5ead02_4 - brotli=1.1.0=h2466b09_3 @@ -26,11 +29,11 @@ dependencies: - brotli-python=1.1.0=py312h275cf98_3 - bwidget=1.10.1=h57928b3_1 - bzip2=1.0.8=h2466b09_7 - - ca-certificates=2025.6.15=h4c7d964_0 + - ca-certificates=2025.7.14=h4c7d964_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h5782bbf_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py312h4389bb4_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - clang=19.1.7=default_hec7ea82_3 @@ -53,10 +56,11 @@ dependencies: - cycler=0.12.1=pyhd8ed1ab_1 - cysignals=1.12.3=py312h275cf98_0 - cython=3.1.2=py312h890cc4b_2 - - debugpy=1.8.14=py312h275cf98_0 + - debugpy=1.8.15=py312ha1a9051_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=he0c23c2_0 - dulwich=0.22.8=py312h2615798_0 @@ -64,7 +68,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=he0c23c2_0 + - expat=2.7.1=hac47afa_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 - flake8-rst-docstrings=0.3.1=pyhd8ed1ab_0 @@ -78,8 +82,8 @@ dependencies: - fontconfig=2.15.0=h765892d_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py312h05f76fc_0 - - fortran-compiler=1.10.0=h95e3450_0 + - fonttools=4.59.0=py312h05f76fc_0 + - fortran-compiler=1.11.0=h95e3450_0 - freetype=2.13.3=h57928b3_1 - furo=2024.8.6=pyhd8ed1ab_2 - gcc_impl_win-64=15.1.0=hb5bc704_3 @@ -94,7 +98,7 @@ dependencies: - gsl=2.7=hdfb1a43_0 - gxx_impl_win-64=15.1.0=h91e354b_3 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=h8796e6f_0 + - harfbuzz=11.3.2=h8796e6f_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he0c23c2_0 @@ -110,17 +114,21 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh5737063_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh7428d3b_0 - kiwisolver=1.4.8=py312hf90b1b7_1 - krb5=1.21.3=hdf4eb48_0 - lcms2=2.17=hbcf6048_0 - - ld_impl_win-64=2.44=hae1bf67_0 + - ld_impl_win-64=2.44=hae1bf67_1 - lerc=4.0.0=h6470a55_1 - libblas=3.9.0=32_h11dc60a_openblas - libboost=1.85.0=h444863b_4 @@ -130,10 +138,10 @@ dependencies: - libbrotlidec=1.1.0=h2466b09_3 - libbrotlienc=1.1.0=h2466b09_3 - libcblas=3.9.0=32_h9bd4c3b_openblas - - libclang13=20.1.7=default_h6e92b77_0 + - libclang13=20.1.8=default_hadf22e1_0 - libcurl=8.14.1=h88aaa65_0 - libdeflate=1.24=h76ddb4d_0 - - libexpat=2.7.0=he0c23c2_0 + - libexpat=2.7.1=hac47afa_0 - libffi=3.4.6=h537db12_1 - libflang=19.1.7=he0c23c2_0 - libflint=3.2.2=h4de658f_0 @@ -157,18 +165,18 @@ dependencies: - libopenblas=0.3.30=pthreads_ha4fe6b2_0 - libpng=1.6.50=h95bef1e_0 - libsodium=1.0.20=hc70643c_0 - - libsqlite=3.50.2=hf5d6505_0 + - libsqlite=3.50.3=hf5d6505_1 - libssh2=1.11.1=h9aa295b_0 - libstdcxx=15.1.0=h904f734_3 - libstdcxx-devel_win-64=15.1.0=hec057c1_103 - libtiff=4.7.0=h05922d8_5 - - libwebp-base=1.5.0=h3b0e114_0 + - libwebp-base=1.6.0=h4d5522a_0 - libwinpthread=12.0.0.r4.gg4f2fc60ca=h57928b3_9 - libxcb=1.17.0=h0e4246c_0 - libxml2=2.13.8=h442d1da_0 - - libxslt=1.1.39=h3df6e99_0 + - libxslt=1.1.43=h25c3957_0 - libzlib=1.3.1=h2466b09_2 - - lld=20.1.7=he99c172_0 + - lld=20.1.8=h5383324_0 - llvm-tools=19.1.7=h2a44499_1 - m2w64-sysroot_win-64=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 - m4ri=20240729=h4afdad8_1 @@ -184,6 +192,7 @@ dependencies: - mingw-w64-ucrt-x86_64-headers-git=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 - mingw-w64-ucrt-x86_64-windows-default-manifest=6.4=he206cdd_7 - mingw-w64-ucrt-x86_64-winpthreads-git=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h72bc38f_1 - mpfr=4.2.1=hbc20e70_3 @@ -191,14 +200,21 @@ dependencies: - msgpack-python=1.1.1=py312hd5eb7cc_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.6.11=h2fa13f4_1 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h79cd779_0 - - numpy=2.3.1=py312h12c3145_0 + - ninja=1.13.1=h477610d_0 + - numpy=2.3.1=py312ha72d056_1 - openblas=0.3.30=pthreads_h4a7f399_0 - openjpeg=2.5.3=h4d64b90_0 - openssl=3.5.1=h725018a_0 - packaging=25.0=pyh29332c3_1 + - pandoc=3.7.0.2=h57928b3_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pari=2.17.2=h7f476ce_4_single - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 @@ -211,7 +227,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py312hfb502af_0 - pip=25.1.1=pyh8b19718_0 - - pixman=0.46.2=had0cd8c_0 + - pixman=0.46.4=hc614b68_0 - pkg-config=0.29.2=h88c491f_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -249,25 +265,27 @@ dependencies: - python-installer=0.7.0=pyhff2d567_1 - python-symengine=0.14.0=py312hda2f51c_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.12=7_cp312 + - python_abi=3.12=8_cp312 - pytz=2025.2=pyhd8ed1ab_0 - - pywin32=307=py312h275cf98_3 + - pywin32=311=py312h829343e_0 - pywin32-ctypes=0.2.3=py312h2e8e312_1 - pyyaml=6.0.2=py312h31fea79_2 - pyzmq=27.0.0=py312hd7027bb_0 - qhull=2020.2=hc790b64_5 - - qt6-main=6.9.1=h02ddd7d_1 + - qt6-main=6.9.1=h02ddd7d_2 - r-base=4.4.3=h80eeea9_2 - r-lattice=0.22_7=r44h11b023d_0 - rapidfuzz=3.13.0=py312h275cf98_0 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py312hdabe01f_0 - ruamel.yaml=0.18.14=py312h4389bb4_0 - ruamel.yaml.clib=0.2.8=py312h4389bb4_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=hd40eec1_0 + - ruff=0.12.4=hd40eec1_0 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 @@ -275,7 +293,7 @@ dependencies: - semver=3.0.4=pyhd8ed1ab_0 - setuptools=80.9.0=pyhff2d567_0 - shellingham=1.5.4=pyhd8ed1ab_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -289,12 +307,13 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hdb435a2_0 + - sqlite=3.50.3=hdb435a2_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h1ba984b_1 - symmetrica=3.0.1=h1537add_0 - sympy=1.14.0=pyh04b8f61_5 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=h2c6b04d_2 - tktable=2.10=h7e9e0db_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -312,14 +331,15 @@ dependencies: - ucrt=10.0.22621.0=h57928b3_1 - unicodedata2=16.0.0=py312h4389bb4_0 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h579f82e_0 - - vc=14.3=h41ae7f8_26 - - vc14_runtime=14.44.35208=h818238b_26 - - virtualenv=20.31.2=pyhd8ed1ab_0 - - vs2015_runtime=14.44.35208=h38c0c73_26 - - vs2022_win-64=19.44.35207=ha74f236_26 + - uv=0.8.2=h579f82e_0 + - vc=14.3=h2b53caa_30 + - vc14_runtime=14.44.35208=h818238b_30 + - virtualenv=20.32.0=pyhd8ed1ab_0 + - vs2015_runtime=14.44.35208=h38c0c73_30 + - vs2022_win-64=19.44.35207=ha74f236_30 - vswhere=3.1.7=h40126e0_1 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - wheel=0.45.1=pyhd8ed1ab_1 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - win_inet_pton=1.1.0=pyh7428d3b_8 diff --git a/environment-3.13-win.yml b/environment-3.13-win.yml index 832047bfd1b..1ca58cbcc73 100644 --- a/environment-3.13-win.yml +++ b/environment-3.13-win.yml @@ -1,7 +1,7 @@ name: sage-dev # Generated by conda-lock. # platform: win-64 -# input_hash: 3476f94b1cc222e860394d68b7aff31cd45865ece8f1a931119ae0e62d975e60 +# input_hash: c1a3d2e3765bd83abcb5bdf4e14c6dcc8526d294e3b1186866d8157c24ff5fc1 channels: - conda-forge @@ -12,13 +12,16 @@ dependencies: - annotated-types=0.7.0=pyhd8ed1ab_1 - appdirs=1.4.4=pyhd8ed1ab_1 - asttokens=3.0.0=pyhd8ed1ab_1 + - attrs=25.3.0=pyh71513ae_0 - babel=2.17.0=pyhd8ed1ab_0 - backports=1.0=pyhd8ed1ab_5 - backports.tarfile=1.2.0=pyhd8ed1ab_1 - beautifulsoup4=4.13.4=pyha770c72_0 - - binutils_impl_win-64=2.44=h095e170_0 + - binutils_impl_win-64=2.44=h095e170_1 - blas=2.132=openblas - blas-devel=3.9.0=32_hc0f8095_openblas + - bleach=6.2.0=pyh29332c3_4 + - bleach-with-css=6.2.0=h82add2a_4 - boltons=25.0.0=pyhd8ed1ab_0 - boost-cpp=1.85.0=ha5ead02_4 - brotli=1.1.0=h2466b09_3 @@ -26,11 +29,11 @@ dependencies: - brotli-python=1.1.0=py313h5813708_3 - bwidget=1.10.1=h57928b3_1 - bzip2=1.0.8=h2466b09_7 - - ca-certificates=2025.6.15=h4c7d964_0 + - ca-certificates=2025.7.14=h4c7d964_0 - cachecontrol=0.14.3=pyha770c72_0 - cachecontrol-with-filecache=0.14.3=pyhd8ed1ab_0 - cairo=1.18.4=h5782bbf_0 - - certifi=2025.6.15=pyhd8ed1ab_0 + - certifi=2025.7.14=pyhd8ed1ab_0 - cffi=1.17.1=py313ha7868ed_0 - charset-normalizer=3.4.2=pyhd8ed1ab_0 - clang=19.1.7=default_hec7ea82_3 @@ -53,10 +56,11 @@ dependencies: - cycler=0.12.1=pyhd8ed1ab_1 - cysignals=1.12.3=py313h5813708_0 - cython=3.1.2=py313h11c7957_2 - - debugpy=1.8.14=py313h5813708_0 + - debugpy=1.8.15=py313h927ade5_0 - decorator=5.2.1=pyhd8ed1ab_0 + - defusedxml=0.7.1=pyhd8ed1ab_0 - deprecated=1.2.18=pyhd8ed1ab_0 - - distlib=0.3.9=pyhd8ed1ab_1 + - distlib=0.4.0=pyhd8ed1ab_0 - docutils=0.21.2=pyhd8ed1ab_1 - double-conversion=3.3.1=he0c23c2_0 - dulwich=0.22.8=py313hf3b5b86_0 @@ -64,7 +68,7 @@ dependencies: - exceptiongroup=1.3.0=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_1 - executing=2.2.0=pyhd8ed1ab_0 - - expat=2.7.0=he0c23c2_0 + - expat=2.7.1=hac47afa_0 - filelock=3.18.0=pyhd8ed1ab_0 - flake8=7.3.0=pyhd8ed1ab_0 - flake8-rst-docstrings=0.3.1=pyhd8ed1ab_0 @@ -78,8 +82,8 @@ dependencies: - fontconfig=2.15.0=h765892d_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.58.5=py313hd650c13_0 - - fortran-compiler=1.10.0=h95e3450_0 + - fonttools=4.59.0=py313hd650c13_0 + - fortran-compiler=1.11.0=h95e3450_0 - freetype=2.13.3=h57928b3_1 - furo=2024.8.6=pyhd8ed1ab_2 - gcc_impl_win-64=15.1.0=hb5bc704_3 @@ -94,7 +98,7 @@ dependencies: - gsl=2.7=hdfb1a43_0 - gxx_impl_win-64=15.1.0=h91e354b_3 - h2=4.2.0=pyhd8ed1ab_0 - - harfbuzz=11.2.1=h8796e6f_0 + - harfbuzz=11.3.2=h8796e6f_0 - hpack=4.1.0=pyhd8ed1ab_0 - hyperframe=6.1.0=pyhd8ed1ab_0 - icu=75.1=he0c23c2_0 @@ -110,17 +114,21 @@ dependencies: - ipywidgets=8.1.7=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_2 - jaraco.context=6.0.1=pyhd8ed1ab_0 - - jaraco.functools=4.1.0=pyhd8ed1ab_0 + - jaraco.functools=4.2.1=pyhd8ed1ab_0 - jedi=0.19.2=pyhd8ed1ab_1 - jinja2=3.1.6=pyhd8ed1ab_0 + - jsonschema=4.25.0=pyhe01879c_0 + - jsonschema-specifications=2025.4.1=pyh29332c3_0 + - jupyter-sphinx=0.5.3=pyha770c72_5 - jupyter_client=8.6.3=pyhd8ed1ab_1 - jupyter_core=5.8.1=pyh5737063_0 + - jupyterlab_pygments=0.3.0=pyhd8ed1ab_2 - jupyterlab_widgets=3.0.15=pyhd8ed1ab_0 - keyring=25.6.0=pyh7428d3b_0 - kiwisolver=1.4.8=py313hf069bd2_1 - krb5=1.21.3=hdf4eb48_0 - lcms2=2.17=hbcf6048_0 - - ld_impl_win-64=2.44=hae1bf67_0 + - ld_impl_win-64=2.44=hae1bf67_1 - lerc=4.0.0=h6470a55_1 - libblas=3.9.0=32_h11dc60a_openblas - libboost=1.85.0=h444863b_4 @@ -130,10 +138,10 @@ dependencies: - libbrotlidec=1.1.0=h2466b09_3 - libbrotlienc=1.1.0=h2466b09_3 - libcblas=3.9.0=32_h9bd4c3b_openblas - - libclang13=20.1.7=default_h6e92b77_0 + - libclang13=20.1.8=default_hadf22e1_0 - libcurl=8.14.1=h88aaa65_0 - libdeflate=1.24=h76ddb4d_0 - - libexpat=2.7.0=he0c23c2_0 + - libexpat=2.7.1=hac47afa_0 - libffi=3.4.6=h537db12_1 - libflang=19.1.7=he0c23c2_0 - libflint=3.2.2=h4de658f_0 @@ -158,18 +166,18 @@ dependencies: - libopenblas=0.3.30=pthreads_ha4fe6b2_0 - libpng=1.6.50=h95bef1e_0 - libsodium=1.0.20=hc70643c_0 - - libsqlite=3.50.2=hf5d6505_0 + - libsqlite=3.50.3=hf5d6505_1 - libssh2=1.11.1=h9aa295b_0 - libstdcxx=15.1.0=h904f734_3 - libstdcxx-devel_win-64=15.1.0=hec057c1_103 - libtiff=4.7.0=h05922d8_5 - - libwebp-base=1.5.0=h3b0e114_0 + - libwebp-base=1.6.0=h4d5522a_0 - libwinpthread=12.0.0.r4.gg4f2fc60ca=h57928b3_9 - libxcb=1.17.0=h0e4246c_0 - libxml2=2.13.8=h442d1da_0 - - libxslt=1.1.39=h3df6e99_0 + - libxslt=1.1.43=h25c3957_0 - libzlib=1.3.1=h2466b09_2 - - lld=20.1.7=he99c172_0 + - lld=20.1.8=h5383324_0 - llvm-tools=19.1.7=h2a44499_1 - m2w64-sysroot_win-64=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 - m4ri=20240729=h4afdad8_1 @@ -185,6 +193,7 @@ dependencies: - mingw-w64-ucrt-x86_64-headers-git=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 - mingw-w64-ucrt-x86_64-windows-default-manifest=6.4=he206cdd_7 - mingw-w64-ucrt-x86_64-winpthreads-git=12.0.0.r4.gg4f2fc60ca=h7428d3b_9 + - mistune=3.1.3=pyh29332c3_0 - more-itertools=10.7.0=pyhd8ed1ab_0 - mpc=1.3.1=h72bc38f_1 - mpfr=4.2.1=hbc20e70_3 @@ -192,14 +201,21 @@ dependencies: - msgpack-python=1.1.1=py313h1ec8472_0 - munkres=1.1.4=pyhd8ed1ab_1 - nauty=2.6.11=h2fa13f4_1 + - nbclient=0.10.2=pyhd8ed1ab_0 + - nbconvert=7.16.6=hb482800_0 + - nbconvert-core=7.16.6=pyh29332c3_0 + - nbconvert-pandoc=7.16.6=hed9df3c_0 + - nbformat=5.10.4=pyhd8ed1ab_1 - nest-asyncio=1.6.0=pyhd8ed1ab_1 - networkx=3.5=pyhe01879c_0 - - ninja=1.13.0=h79cd779_0 - - numpy=2.3.1=py313ha14762d_0 + - ninja=1.13.1=h477610d_0 + - numpy=2.3.1=py313hce7ae62_1 - openblas=0.3.30=pthreads_h4a7f399_0 - openjpeg=2.5.3=h4d64b90_0 - openssl=3.5.1=h725018a_0 - packaging=25.0=pyh29332c3_1 + - pandoc=3.7.0.2=h57928b3_0 + - pandocfilters=1.5.0=pyhd8ed1ab_0 - pari=2.17.2=h7f476ce_4_single - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 @@ -212,7 +228,7 @@ dependencies: - pickleshare=0.7.5=pyhd8ed1ab_1004 - pillow=11.3.0=py313h641beac_0 - pip=25.1.1=pyh145f28c_0 - - pixman=0.46.2=had0cd8c_0 + - pixman=0.46.4=hc614b68_0 - pkg-config=0.29.2=h88c491f_1009 - pkgconfig=1.5.5=pyhd8ed1ab_5 - pkginfo=1.12.1.2=pyhd8ed1ab_0 @@ -250,25 +266,27 @@ dependencies: - python-installer=0.7.0=pyhff2d567_1 - python-symengine=0.14.0=py313h9ea13ff_1 - python-utils=3.9.1=pyhff2d567_1 - - python_abi=3.13=7_cp313 + - python_abi=3.13=8_cp313 - pytz=2025.2=pyhd8ed1ab_0 - - pywin32=307=py313h5813708_3 + - pywin32=311=py313h40c08fc_0 - pywin32-ctypes=0.2.3=py313hfa70ccb_1 - pyyaml=6.0.2=py313hb4c8b1a_2 - pyzmq=27.0.0=py313h2100fd5_0 - qhull=2020.2=hc790b64_5 - - qt6-main=6.9.1=h02ddd7d_1 + - qt6-main=6.9.1=h02ddd7d_2 - r-base=4.4.3=h80eeea9_2 - r-lattice=0.22_7=r44h11b023d_0 - rapidfuzz=3.13.0=py313h5813708_0 + - referencing=0.36.2=pyh29332c3_0 - requests=2.32.4=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_1 - restructuredtext_lint=1.4.0=pyhd8ed1ab_1 - roman-numerals-py=3.1.0=pyhd8ed1ab_0 + - rpds-py=0.26.0=py313hfbe8231_0 - ruamel.yaml=0.18.14=py313ha7868ed_0 - ruamel.yaml.clib=0.2.8=py313ha7868ed_1 - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_1 - - ruff=0.12.2=hd40eec1_0 + - ruff=0.12.4=hd40eec1_0 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 @@ -276,7 +294,7 @@ dependencies: - semver=3.0.4=pyhd8ed1ab_0 - setuptools=80.9.0=pyhff2d567_0 - shellingham=1.5.4=pyhd8ed1ab_1 - - six=1.17.0=pyhd8ed1ab_0 + - six=1.17.0=pyhe01879c_1 - smmap=5.0.2=pyhd8ed1ab_0 - snowballstemmer=3.0.1=pyhd8ed1ab_0 - soupsieve=2.7=pyhd8ed1ab_0 @@ -290,12 +308,13 @@ dependencies: - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 - - sqlite=3.50.2=hdb435a2_0 + - sqlite=3.50.3=hdb435a2_1 - stack_data=0.6.3=pyhd8ed1ab_1 - stdlib-list=0.11.1=pyhd8ed1ab_0 - symengine=0.14.0=h1ba984b_1 - symmetrica=3.0.1=h1537add_0 - sympy=1.14.0=pyh04b8f61_5 + - tinycss2=1.4.0=pyhd8ed1ab_0 - tk=8.6.13=h2c6b04d_2 - tktable=2.10=h7e9e0db_7 - toml=0.10.2=pyhd8ed1ab_1 @@ -312,14 +331,15 @@ dependencies: - tzdata=2025b=h78e105d_0 - ucrt=10.0.22621.0=h57928b3_1 - urllib3=2.5.0=pyhd8ed1ab_0 - - uv=0.7.19=h579f82e_0 - - vc=14.3=h41ae7f8_26 - - vc14_runtime=14.44.35208=h818238b_26 - - virtualenv=20.31.2=pyhd8ed1ab_0 - - vs2015_runtime=14.44.35208=h38c0c73_26 - - vs2022_win-64=19.44.35207=ha74f236_26 + - uv=0.8.2=h579f82e_0 + - vc=14.3=h2b53caa_30 + - vc14_runtime=14.44.35208=h818238b_30 + - virtualenv=20.32.0=pyhd8ed1ab_0 + - vs2015_runtime=14.44.35208=h38c0c73_30 + - vs2022_win-64=19.44.35207=ha74f236_30 - vswhere=3.1.7=h40126e0_1 - wcwidth=0.2.13=pyhd8ed1ab_1 + - webencodings=0.5.1=pyhd8ed1ab_3 - widgetsnbextension=4.0.14=pyhd8ed1ab_0 - win_inet_pton=1.1.0=pyh7428d3b_8 - winpthreads-devel=12.0.0.r4.gg4f2fc60ca=h57928b3_9 diff --git a/meson.options b/meson.options new file mode 100644 index 00000000000..7cb90abe462 --- /dev/null +++ b/meson.options @@ -0,0 +1,9 @@ +## Options for the Meson build system +# https://mesonbuild.com/Build-options.html + +option( + 'SAGE_LOCAL', + type: 'string', + value: '', + description: 'Path to SAGE_LOCAL directory (only used for compatibility with the old Sage-the-Distro', +) diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sage-conf/_sage_conf/_conf.py.in b/pkgs/sage-conf/_sage_conf/_conf.py.in index e5386cf89cf..eb45225eee4 100644 --- a/pkgs/sage-conf/_sage_conf/_conf.py.in +++ b/pkgs/sage-conf/_sage_conf/_conf.py.in @@ -21,6 +21,7 @@ MAXIMA = "@SAGE_MAXIMA@".replace('${prefix}', SAGE_LOCAL) # Set this to the empty string if your ECL can load maxima without # further prodding. MAXIMA_FAS = "@SAGE_MAXIMA_FAS@".replace('${prefix}', SAGE_LOCAL) +MAXIMA_SHARE = "@SAGE_MAXIMA_SHARE@".replace('${prefix}', SAGE_LOCAL) # Delete this line if your ECL can load Kenzo without further prodding. KENZO_FAS = "@SAGE_KENZO_FAS@".replace('${prefix}', SAGE_LOCAL) diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/pyproject.toml b/pyproject.toml index 01416920657..d4d023ae190 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,16 +2,16 @@ build-backend = 'mesonpy' # Minimum requirements for the build system to execute. requires = [ - 'meson-python', - 'cypari2 >=2.2.1; sys_platform != "win32"', - # Exclude 1.12.0 because of https://github.com/sagemath/cysignals/issues/212 - 'cysignals >=1.11.2, != 1.12.0', - # Exclude 3.0.3 because of https://github.com/cython/cython/issues/5748 - 'cython >=3.0, != 3.0.3', - 'gmpy2 ~=2.1.b999', - 'memory_allocator', - 'numpy >=1.25', - 'jinja2' + 'meson-python', + 'cypari2 >=2.2.1; sys_platform != "win32"', + # Exclude 1.12.0 because of https://github.com/sagemath/cysignals/issues/212 + 'cysignals >=1.11.2, != 1.12.0', + # Exclude 3.0.3 because of https://github.com/cython/cython/issues/5748 + 'cython >=3.0, != 3.0.3', + 'gmpy2 ~=2.1.b999', + 'memory_allocator', + 'numpy >=1.25', + 'jinja2', ] [tool.meson-python.args] # Prevent meson from trying to install the autoconf subprojects @@ -28,75 +28,75 @@ setup = ['--default-library=static'] name = "sagemath" description = "Sage: Open Source Mathematics Software: Standard Python Library" dependencies = [ - 'six >=1.15.0', - 'conway-polynomials >=0.8', - 'cypari2 >=2.2.1; sys_platform != "win32"', - # Exclude 1.12.0 because of https://github.com/sagemath/cysignals/issues/212 - 'cysignals >=1.11.2, != 1.12.0', - 'cython >=3.0, != 3.0.3', - 'gmpy2 ~=2.1.b999', - 'lrcalc ~=2.1; sys_platform != "win32"', - 'memory_allocator', - 'numpy >=1.25', - # Issue #30922: pplpy 0.8.4 and earlier do not declare dependencies correctly - 'pplpy >=0.8.6; sys_platform != "win32"', - 'primecountpy; sys_platform != "win32"', - 'requests >=2.13.0', - # According to https://github.com/python/typing_extensions/blob/main/CHANGELOG.md, - # version 4.4.0 adds another Python 3.11 typing backport - 'typing_extensions >= 4.4.0; python_version<"3.11"', - 'ipython >=8.9.0', - 'pexpect >=4.8.0', - 'platformdirs', - 'sphinx >=5.2, <9', - 'networkx >=3.1', - 'scipy >=1.11', - 'sympy >=1.6, <2.0', - 'matplotlib >=3.7.0', - 'pillow >=7.2.0', - 'mpmath >=1.1.0', - 'ipykernel >=5.2.1', - 'jupyter-client', - 'ipywidgets >=7.5.1', - 'fpylll >=0.5.9; sys_platform != "win32"', - 'ptyprocess > 0.5', - # TODO: Remove this once the migration to meson is complete - 'pkgconfig', - 'traitlets', + 'six >=1.15.0', + 'conway-polynomials >=0.8', + 'cypari2 >=2.2.1; sys_platform != "win32"', + # Exclude 1.12.0 because of https://github.com/sagemath/cysignals/issues/212 + 'cysignals >=1.11.2, != 1.12.0', + 'cython >=3.0, != 3.0.3', + 'gmpy2 ~=2.1.b999', + 'memory_allocator', + 'numpy >=1.25', + # Issue #30922: pplpy 0.8.4 and earlier do not declare dependencies correctly + 'pplpy >=0.8.6; sys_platform != "win32"', + 'primecountpy; sys_platform != "win32"', + 'requests >=2.13.0', + # According to https://github.com/python/typing_extensions/blob/main/CHANGELOG.md, + # version 4.4.0 adds another Python 3.11 typing backport + 'typing_extensions >= 4.4.0; python_version<"3.11"', + 'ipython >=8.9.0', + 'pexpect >=4.8.0', + 'platformdirs', + 'sphinx >=5.2, <9', + 'networkx >=3.1', + 'scipy >=1.11', + 'sympy >=1.6, <2.0', + 'matplotlib >=3.7.0', + 'pillow >=7.2.0', + 'mpmath >=1.1.0', + 'ipykernel >=5.2.1', + 'jupyter-client', + 'ipywidgets >=7.5.1', + 'fpylll >=0.5.9; sys_platform != "win32"', + 'ptyprocess > 0.5', + # TODO: Remove this once the migration to meson is complete + 'pkgconfig', + 'traitlets', ] dynamic = ["version"] -license = {text = "GNU General Public License (GPL) v2 or later"} -authors = [{name = "The Sage Developers", email = "sage-support@googlegroups.com"}] -classifiers = [ - "Development Status :: 6 - Mature", - "Intended Audience :: Education", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", - "Operating System :: POSIX", - "Operating System :: MacOS :: MacOS X", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: Implementation :: CPython", - "Topic :: Scientific/Engineering :: Mathematics", +license = { text = "GNU General Public License (GPL) v2 or later" } +authors = [ + { name = "The Sage Developers", email = "sage-support@googlegroups.com" }, ] -urls = {Homepage = "https://www.sagemath.org"} +classifiers = [ + "Development Status :: 6 - Mature", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Scientific/Engineering :: Mathematics", +] +urls = { Homepage = "https://www.sagemath.org" } requires-python = ">=3.11, <3.14" [project.optional-dependencies] R = ['rpy2 >=3.3'] extra = [ - 'p_group_cohomology >=3.3', # Only used in tests + 'p_group_cohomology >=3.3', # Only used in tests 'pycosat >=0.6.3', 'pynormaliz >=2.18; platform_machine != "aarch64" and platform_machine != "arm64"', # Not yet available for Linux aarch64 'igraph', 'sage_numerical_backends_coin', - 'symengine >= 0.6.1', # Only used in tests -] -giac = [ - 'sagemath_giac', + 'symengine >= 0.6.1', # Only used in tests + 'lrcalc ~=2.1; sys_platform != "win32"', ] +giac = ['sagemath_giac'] [project.readme] file = "README.md" @@ -106,9 +106,7 @@ content-type = "text/markdown" sage = "sage.cli:main" [tool.conda-lock] -platforms = [ - 'osx-64', 'linux-64', 'linux-aarch64', 'osx-arm64' -] +platforms = ['osx-64', 'linux-64', 'linux-aarch64', 'osx-arm64'] [tool.pytest.ini_options] python_files = "*_test.py" @@ -209,33 +207,17 @@ extra = [ ] [dependency-groups] -test = [ - "pytest", - "pytest-xdist", - "coverage", -] +test = ["pytest", "pytest-xdist", "coverage"] docs = [ - "sphinx", + "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", + "jupyter-sphinx", "furo", "python-dateutil", ] -lint = [ - "relint", - "ruff", - "pycodestyle", - "flake8-rst-docstrings", -] -dev = [ - "tqdm", - "pygithub", - "meson", - "conda-lock", - "grayskull", - "toml", - "uv", -] +lint = ["relint", "ruff", "pycodestyle", "flake8-rst-docstrings"] +dev = ["tqdm", "pygithub", "meson", "conda-lock", "grayskull", "toml", "uv"] [tool.ruff] # https://docs.astral.sh/ruff/configuration @@ -245,9 +227,9 @@ target-version = "py311" [tool.ruff.lint] select = [ - "E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e - "F", # pyflakes - https://docs.astral.sh/ruff/rules/#pyflakes-f - "I", # isort - https://docs.astral.sh/ruff/rules/#isort-i + "E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e + "F", # pyflakes - https://docs.astral.sh/ruff/rules/#pyflakes-f + "I", # isort - https://docs.astral.sh/ruff/rules/#isort-i "PL", # pylint - https://docs.astral.sh/ruff/rules/#pylint-pl ] ignore = [ diff --git a/src/VERSION.txt b/src/VERSION.txt index 361d1a1aa7b..daf88a39ff5 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.7.beta9 +10.7.rc0 diff --git a/src/bin/math-readline b/src/bin/math-readline index 455c950ba25..b9534f2f2fe 100755 --- a/src/bin/math-readline +++ b/src/bin/math-readline @@ -1,15 +1,17 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 # Cleverly run Mathematica with the benefit of readline, which # is something the usual commercial mathematica doesn't provide! # See # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/363500 -import sys import signal import subprocess +import sys + from sage.cpython.string import str_to_bytes + def child_exited(*args): global child status = child.poll() diff --git a/src/bin/sage b/src/bin/sage index 12248f435df..ed4b7895e40 100755 --- a/src/bin/sage +++ b/src/bin/sage @@ -578,7 +578,6 @@ fi if [ "$1" = '-c' ]; then shift sage_setup - unset TERM # See Issue #12263 exec sage-eval "$@" fi @@ -944,7 +943,7 @@ fi if [ "$1" = '-fixdistributions' -o "$1" = '--fixdistributions' ]; then shift - exec sage-python -m sage.misc.package_dir "$@" + exec python3 -m sage.misc.package_dir "$@" fi if [ "$1" = '-tox' -o "$1" = '--tox' ]; then @@ -1012,7 +1011,7 @@ if [ "$1" = "-docbuild" -o "$1" = "--docbuild" ]; then # Redirect stdin from /dev/null. This helps with running TeX which # tends to ask interactive questions if something goes wrong. These # cause the build to hang. If stdin is /dev/null, TeX just aborts. - exec sage-python -m sage_docbuild "$@" 1: diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 9877af91cc8..520719d2506 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -1,4 +1,4 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 """ Given the output of doctest and a file, adjust the doctests so they won't fail. diff --git a/src/bin/sage-ipython b/src/bin/sage-ipython index e87c363919a..86b91f63566 100755 --- a/src/bin/sage-ipython +++ b/src/bin/sage-ipython @@ -1,4 +1,4 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Sage IPython startup script. @@ -7,6 +7,7 @@ Sage IPython startup script. # Display startup banner. Do this before anything else to give the user # early feedback that Sage is starting. from sage.misc.banner import banner + banner() from sage.repl.interpreter import SageTerminalApp diff --git a/src/bin/sage-list-packages b/src/bin/sage-list-packages index ea10b932cc9..637fab8dd4f 100755 --- a/src/bin/sage-list-packages +++ b/src/bin/sage-list-packages @@ -1,4 +1,4 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 r""" Script to list the Sage packages diff --git a/src/bin/sage-massif b/src/bin/sage-massif index 083831d9293..a031f1ef022 100755 --- a/src/bin/sage-massif +++ b/src/bin/sage-massif @@ -21,5 +21,5 @@ else echo $MASSIF_FLAGS fi -valgrind --tool=massif $MASSIF_FLAGS sage-python -i +valgrind --tool=massif $MASSIF_FLAGS python3 -i diff --git a/src/bin/sage-notebook b/src/bin/sage-notebook index 8cb0d1fa9a6..5f2be689487 100755 --- a/src/bin/sage-notebook +++ b/src/bin/sage-notebook @@ -1,12 +1,10 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 # -*- coding: utf-8; mode: python -*- -import os -import sys -import ast import argparse import logging -import textwrap +import os +import sys from contextlib import contextmanager logging.basicConfig() @@ -14,7 +12,6 @@ logger = logging.getLogger() from sage.misc.banner import banner - _system_jupyter_url = "https://doc.sagemath.org/html/en/installation/launching.html#setting-up-sagemath-as-a-jupyter-kernel-in-an-existing-jupyter-notebook-or-jupyterlab-installation" @@ -188,7 +185,9 @@ def sage_doc_server(): from functools import partial from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from threading import Thread - from sage.env import SAGE_DOC, SAGE_DOC_LOCAL_PORT as port + + from sage.env import SAGE_DOC + from sage.env import SAGE_DOC_LOCAL_PORT as port server = ThreadingHTTPServer(('127.0.0.1', int(port)), partial(SimpleHTTPRequestHandler, directory=SAGE_DOC)) diff --git a/src/bin/sage-omega b/src/bin/sage-omega index b0f0f981106..b401d358b8a 100755 --- a/src/bin/sage-omega +++ b/src/bin/sage-omega @@ -21,5 +21,5 @@ else echo $OMEGA_FLAGS fi -valgrind --tool=exp-omega $OMEGA_FLAGS sage-python -i +valgrind --tool=exp-omega $OMEGA_FLAGS python3 -i diff --git a/src/bin/sage-preparse b/src/bin/sage-preparse index 3422d236bf2..aeb36c92675 100755 --- a/src/bin/sage-preparse +++ b/src/bin/sage-preparse @@ -1,4 +1,4 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 """ Preparse .sage files and save the result to .sage.py files. @@ -11,11 +11,11 @@ AUTHOR: """ import os -import sys import re +import sys -from sage.repl.preparse import preparse_file from sage.misc.temporary_file import atomic_write +from sage.repl.preparse import preparse_file # The spkg/bin/sage script passes the files to be preparsed as # arguments (but remove sys.argv[0]). diff --git a/src/bin/sage-python b/src/bin/sage-python deleted file mode 100755 index 596a467e242..00000000000 --- a/src/bin/sage-python +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -sage -python "$@" diff --git a/src/bin/sage-run b/src/bin/sage-run index d4129e1c6b2..49509aeccb2 100755 --- a/src/bin/sage-run +++ b/src/bin/sage-run @@ -1,6 +1,7 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 -import os, sys +import os +import sys from subprocess import call if len(sys.argv) < 2: @@ -20,8 +21,8 @@ if fn.startswith('-'): if fn.endswith('.sage'): if call(['sage-preparse', fn]) != 0: sys.exit(1) - os.execvp('sage-python', ['sage-python', fn + '.py'] + opts) + os.execvp('python3', ['python3', fn + '.py'] + opts) elif fn.endswith('.pyx') or fn.endswith('.spyx'): os.execvp('sage-run-cython', ['sage-run-cython', fn] + opts) else: - os.execvp('sage-python', ['sage-python', fn] + opts) + os.execvp('python3', ['python3', fn] + opts) diff --git a/src/bin/sage-run-cython b/src/bin/sage-run-cython index b4cabe039ff..365809d7ef0 100755 --- a/src/bin/sage-run-cython +++ b/src/bin/sage-run-cython @@ -1,10 +1,10 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 import sys -from sage.repl.load import load_cython + from sage.misc.temporary_file import tmp_filename +from sage.repl.load import load_cython if len(sys.argv) > 1: s = load_cython(sys.argv.pop(1)) - import sage.all eval(compile(s, tmp_filename(), 'exec')) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 8ab309685c7..ced6d30ebb1 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -1,9 +1,8 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 import sys from sage.doctest.__main__ import main - if __name__ == "__main__": sys.exit(main()) diff --git a/src/bin/sage-startuptime.py b/src/bin/sage-startuptime.py index 095373568f8..9bda64ef19a 100755 --- a/src/bin/sage-startuptime.py +++ b/src/bin/sage-startuptime.py @@ -1,4 +1,4 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 ######################################################################## # Originally based on a script by Andrew Dalke: diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 6fdd194e8c8..c28f05b8025 100755 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the update-version script, do not edit! -SAGE_VERSION='10.7.beta9' -SAGE_RELEASE_DATE='2025-07-25' -SAGE_VERSION_BANNER='SageMath version 10.7.beta9, Release Date: 2025-07-25' +SAGE_VERSION='10.7.rc0' +SAGE_RELEASE_DATE='2025-08-02' +SAGE_VERSION_BANNER='SageMath version 10.7.rc0, Release Date: 2025-08-02' diff --git a/src/build-docs.py b/src/build-docs.py index 2fa1c4f718e..ec5ff92da7c 100644 --- a/src/build-docs.py +++ b/src/build-docs.py @@ -1,3 +1,10 @@ +# Add the current directory to the end of sys.path +# to ensure that an installed version of sage is used first. +import sys + +current_dir = sys.path.pop(0) +sys.path.append(current_dir) + from sage_docbuild.__main__ import main if __name__ == "__main__": diff --git a/src/conftest_inputtest.py b/src/conftest_inputtest.py deleted file mode 100644 index aeca6276691..00000000000 --- a/src/conftest_inputtest.py +++ /dev/null @@ -1,16 +0,0 @@ -def something(): - """ a doctest in a docstring - - EXAMPLES:: - - sage: something() - 42 - sage: something() + 1 - 43 - - TESTS:: - - sage: something() - 44 - """ - return 42 diff --git a/src/conftest_test.py b/src/conftest_test.py deleted file mode 100644 index fe790c48bb9..00000000000 --- a/src/conftest_test.py +++ /dev/null @@ -1,57 +0,0 @@ -from pathlib import Path -import subprocess - - -from sage.env import SAGE_SRC - -input_file = Path(SAGE_SRC) / "conftest_inputtest.py" - - -class TestOldDoctestSageScript: - """Run `sage --t`.""" - - def test_invoke_on_inputtest_file(self): - result = subprocess.run( - ["sage", "-t", input_file], - capture_output=True, - text=True, - ) - assert result.returncode == 1 # There are failures in the input test - assert ( - "Failed example:\n" - " something()\n" - "Expected:\n" - " 44\n" - "Got:\n" - " 42\n" - "" in result.stdout - ) - - -class TestPytestSageScript: - """Run `sage --pytest`.""" - - def test_invoke_on_inputtest_file(self): - result = subprocess.run( - ["sage", "--pytest", input_file], - capture_output=True, - text=True, - ) - assert result.returncode == 1 # There are failures in the input test - assert ( - "004 EXAMPLES::\n" - "005 \n" - "006 sage: something()\n" - "007 42\n" - "008 sage: something() + 1\n" - "009 43\n" - "010 \n" - "011 TESTS::\n" - "012 \n" - "013 sage: something()\n" - "Expected:\n" - " 44\n" - "Got:\n" - " 42\n" - "" in result.stdout - ) diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index ae68b94bb9b..bdfae915090 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -347,10 +347,6 @@ Likewise for :envvar:`CXXFLAGS`, :envvar:`FCFLAGS`, and :envvar:`F77FLAGS`. python3. You should use this if you are installing a Python package to make sure that the libraries are installed in the right place. - By the way, there is also a script ``sage-python``. This should be - used at runtime, for example in scripts in ``SAGE_LOCAL/bin`` which - expect Sage's Python to already be built. - Many packages currently do not separate the build and install steps and only provide a ``spkg-install.in`` file that does both. The separation is useful in particular for root-owned install hierarchies, where something like ``sudo`` diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 2a8aa1059f7..f1c3bfe5cca 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1003,7 +1003,7 @@ on every release tag. This is defined in the files -- :sage_root:`.github/workflows/ci-linux.yml` +- :sage_root:`.github/workflows/ci-distro.yml` (which calls :sage_root:`.github/workflows/docker.yml`) and - :sage_root:`.github/workflows/ci-macos.yml` diff --git a/src/doc/en/prep/Logging-On.rst b/src/doc/en/prep/Logging-On.rst index e434cc3bcd5..acd16f8c8ba 100644 --- a/src/doc/en/prep/Logging-On.rst +++ b/src/doc/en/prep/Logging-On.rst @@ -54,7 +54,7 @@ the third option to "export" them will not make sense. The legacy SageNB has been retired in Sage 9.1. Please use the Jupyter notebook. Old SageNB worksheets can be converted to Jupyter notebooks -using the `sage --notebook=export` command or to RST +using the ``sage --notebook=export`` command or to RST using the `sage-sws2rst `_ package. Jupyter will bring you to a screen diff --git a/src/doc/en/prep/Programming.rst b/src/doc/en/prep/Programming.rst index e70b4cd93f7..dd7d50762f1 100644 --- a/src/doc/en/prep/Programming.rst +++ b/src/doc/en/prep/Programming.rst @@ -109,7 +109,7 @@ It is very important to keep in the parentheses. :: sage: A.det # Won't work - + This is so useful because we can use the 'tab' key, remember! diff --git a/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst b/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst index c97efdecee4..aeb2b01a450 100644 --- a/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst +++ b/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst @@ -178,7 +178,7 @@ This is a good place for a few reminders of basic help. :: sage: z.simplify - + Finally, recall that you can get nicely typeset versions of the output in several ways. diff --git a/src/doc/meson.build b/src/doc/meson.build index dedbe0b60c0..7b3692fa5f0 100644 --- a/src/doc/meson.build +++ b/src/doc/meson.build @@ -1,3 +1,11 @@ +sphinx_check = py_module.find_installation(required: false, modules: ['sphinx']) +if not sphinx_check.found() + warning( + 'Python package "sphinx" is not installed. Documentation build not enabled.', + ) + subdir_done() +endif + doc_src = [] subdir('en/reference/repl') # TODO: Migrate this completely to meson diff --git a/src/meson.build b/src/meson.build index 335f35d5823..cd35834c9b8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -131,7 +131,18 @@ if not gd.found() endif # Only some platforms have a standalone math library (https://mesonbuild.com/howtox.html#add-math-library-lm-portably) m = cc.find_library('m', required: false) -m4ri = dependency('m4ri', version: '>=20140914') +m4ri = dependency('m4ri', version: '>=20250128', required: false) +if not m4ri.found() + # Older versions of m4ri are declaring "@SIMD_CFLAGS@" as compile_args + # which breaks the build. So we exclude these compile args. + # https://github.com/malb/m4ri/commit/3197be5f7d3c67e8f13e32516557f35cbf4ff6ce + m4ri = dependency('m4ri', version: '>=20140914').partial_dependency( + includes: true, + link_args: true, + links: true, + sources: true, + ) +endif m4rie = dependency('m4rie', required: false) if not m4rie.found() # For some reason, m4rie is not found via pkg-config on some systems (eg Conda) @@ -149,8 +160,9 @@ zlib = dependency('zlib', version: '>=1.2.11') # We actually want >= 20231212, but the version number is not updated in the pkgconfig # https://github.com/conda-forge/eclib-feedstock/issues/48 ec = dependency('eclib', version: '>=20231211', required: false, disabler: true) -# Cannot be found via pkg-config -ec = cc.find_library('ec', required: not is_windows, disabler: true) +if not ec.found() + ec = cc.find_library('ec', required: false, disabler: true) +endif ecm = cc.find_library('ecm', required: not is_windows, disabler: true) gmpxx = dependency('gmpxx', required: not is_windows, disabler: true) fflas = dependency( @@ -195,7 +207,6 @@ else singular_proj = subproject('singular') singular_factory = singular_proj.get_variable('factory_dep') endif -maxima = find_program('maxima', required: not is_windows, disabler: true) # Cannot be found via pkg-config ntl = cc.find_library('ntl', required: not is_windows, disabler: true) @@ -208,7 +219,7 @@ add_project_arguments('-I', meson.current_build_dir(), language: 'cython') # Add global compiler flags add_project_arguments('-X auto_pickle=False', language: 'cython') add_project_arguments('-X autotestdict=False', language: 'cython') -add_project_arguments('-X binding=False', language: 'cython') +add_project_arguments('-X binding=True', language: 'cython') add_project_arguments('-X c_api_binop_methods=True', language: 'cython') add_project_arguments('-X cdivision=True', language: 'cython') add_project_arguments('-X cpow=True', language: 'cython') diff --git a/src/sage/algebras/clifford_algebra_element.pyi b/src/sage/algebras/clifford_algebra_element.pyi new file mode 100644 index 00000000000..56c4ff7220e --- /dev/null +++ b/src/sage/algebras/clifford_algebra_element.pyi @@ -0,0 +1,29 @@ +from typing import Any + +class CliffordAlgebraElement: + def _repr_(self) -> str: ... + def _latex_(self) -> str: ... + def _mul_(self, other: CliffordAlgebraElement) -> CliffordAlgebraElement: ... + def _mul_self_term(self, supp: Any, coeff: Any) -> CliffordAlgebraElement: ... + def _mul_term_self(self, supp: Any, coeff: Any) -> CliffordAlgebraElement: ... + def list(self) -> list[tuple[Any, Any]]: ... + def support(self) -> list[Any]: ... + def reflection(self) -> CliffordAlgebraElement: ... + degree_negation = reflection + def transpose(self) -> CliffordAlgebraElement: ... + def conjugate(self) -> CliffordAlgebraElement: ... + clifford_conjugate = conjugate + +class ExteriorAlgebraElement(CliffordAlgebraElement): + def _mul_(self, other: ExteriorAlgebraElement) -> ExteriorAlgebraElement: ... + def _mul_self_term(self, supp: Any, coeff: Any) -> ExteriorAlgebraElement: ... + def _mul_term_self(self, supp: Any, coeff: Any) -> ExteriorAlgebraElement: ... + def reduce(self, I: Any, left: bool = True) -> ExteriorAlgebraElement: ... + def interior_product(self, x: Any) -> ExteriorAlgebraElement: ... + antiderivation = interior_product + def hodge_dual(self) -> ExteriorAlgebraElement: ... + def constant_coefficient(self) -> Any: ... + def scalar(self, other: ExteriorAlgebraElement) -> Any: ... + +class CohomologyRAAGElement(CliffordAlgebraElement): + def _mul_(self, other: CohomologyRAAGElement) -> CohomologyRAAGElement: ... diff --git a/src/sage/algebras/exterior_algebra_groebner.pyi b/src/sage/algebras/exterior_algebra_groebner.pyi new file mode 100644 index 00000000000..7aff993da24 --- /dev/null +++ b/src/sage/algebras/exterior_algebra_groebner.pyi @@ -0,0 +1,44 @@ +from collections.abc import Set +from typing import Any + +class GBElement: + def __init__(self, x: Any, ls: Any, n: int) -> None: ... + def __hash__(self) -> int: ... + def __richcmp__(self, other: Any, op: int) -> Any: ... + +class GroebnerStrategy: + def __init__(self, I: Any) -> None: ... + def leading_support(self, f: Any) -> Any: ... + def partial_S_poly_left(self, f: GBElement, g: GBElement) -> GBElement: ... + def partial_S_poly_right(self, f: GBElement, g: GBElement) -> GBElement: ... + def build_elt(self, f: Any) -> GBElement: ... + def prod_GB_term(self, f: GBElement, t: Any) -> GBElement: ... + def prod_term_GB(self, t: Any, f: GBElement) -> GBElement: ... + def build_S_poly(self, f: GBElement, g: GBElement) -> bool: ... + def preprocessing( + self, P: list[tuple[GBElement, GBElement]], G: list[GBElement] + ) -> Set[GBElement]: ... + def reduction( + self, P: list[tuple[GBElement, GBElement]], G: list[GBElement] + ) -> list[GBElement]: ... + def compute_groebner(self, reduced: bool = True) -> None: ... + def reduced_gb(self, G: list[GBElement]) -> int: ... + def reduce_computed_gb(self) -> None: ... + def reduce(self, f: Any) -> Any: ... + def reduce_single(self, f: Any, g: Any) -> bool: ... + def bitset_to_int(self, X: Any) -> int: ... + def int_to_bitset(self, n: int) -> Any: ... + def sorted_monomials(self, as_dict: bool = False) -> list[Any]: ... + def monomial_to_int(self) -> dict: ... + +class GroebnerStrategyNegLex(GroebnerStrategy): + def bitset_to_int(self, X: Any) -> int: ... + def int_to_bitset(self, n: int) -> Any: ... + +class GroebnerStrategyDegRevLex(GroebnerStrategy): + def bitset_to_int(self, X: Any) -> int: ... + def int_to_bitset(self, n: int) -> Any: ... + +class GroebnerStrategyDegLex(GroebnerStrategy): + def bitset_to_int(self, X: Any) -> int: ... + def int_to_bitset(self, n: int) -> Any: ... diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index b5554d901f5..5777fec0fc9 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -5,6 +5,7 @@ AUTHORS: - Travis Scrimshaw (2013-09-06): Initial version +- Joseph McDonough (2025-06-13): Added ``InfGenDifferentialWeylAlgebra`` """ # **************************************************************************** @@ -25,12 +26,14 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.action import Action from sage.categories.rings import Rings -from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.cartesian_product import cartesian_product from sage.sets.family import Family import sage.data_structures.blas_dict as blas from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.infinite_polynomial_ring import InfinitePolynomialRing_dense +from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial from sage.structure.global_options import GlobalOptions from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement @@ -257,6 +260,13 @@ class DifferentialWeylAlgebraElement(IndexedFreeModuleElement): False sage: x + 1 == 1 False + sage: a = (x*y + z) * dx + sage: 3/2 * a + 3/2*x*y*dx + 3/2*z*dx + sage: a * 3/2 + 3/2*x*y*dx + 3/2*z*dx + sage: a / 2 + 1/2*x*y*dx + 1/2*z*dx sage: W(x^3 - y*z) == x^3 - y*z True sage: W. = DifferentialWeylAlgebra(QQ) @@ -665,7 +675,7 @@ class DifferentialWeylAlgebra(UniqueRepresentation, Parent): they are considered to be graded rings (algebras). """ @staticmethod - def __classcall__(cls, R, names=None): + def __classcall_private__(cls, R, names=None, n=None): """ Normalize input to ensure a unique representation. @@ -676,17 +686,22 @@ def __classcall__(cls, R, names=None): sage: W1 is W2 True """ + from sage.rings.infinity import PlusInfinity + if n is PlusInfinity(): # hook for Infinite weyl algebra + return InfGenDifferentialWeylAlgebra(R, names) if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): if names is None: names = R.variable_names() R = R.base_ring() + elif isinstance(R, InfinitePolynomialRing_dense) and names is None: + return InfGenDifferentialWeylAlgebra(R.base_ring(), R.variable_names()) elif names is None: raise ValueError("the names must be specified") elif R not in Rings().Commutative(): raise TypeError("argument R must be a commutative ring") return super().__classcall__(cls, R, names) - def __init__(self, R, names=None) -> None: + def __init__(self, R, names=None, n=None) -> None: r""" Initialize ``self``. @@ -696,6 +711,8 @@ def __init__(self, R, names=None) -> None: sage: W = DifferentialWeylAlgebra(R) sage: TestSuite(W).run() """ + from sage.categories.algebras_with_basis import AlgebrasWithBasis + self._n = len(names) self._poly_ring = PolynomialRing(R, names) names = names + tuple('d' + n for n in names) @@ -899,13 +916,13 @@ def basis(self): def elt_map(u): return (tuple(u[:n]), tuple(u[n:])) - I = IntegerListsNN(length=2 * n, element_constructor=elt_map) + index_set = IntegerListsNN(length=2 * n, element_constructor=elt_map) one = self.base_ring().one() def f(x): return self.element_class(self, {(x[0], x[1]): one}) - return Family(I, f, name="basis map") + return Family(index_set, f, name="basis map") @cached_method def algebra_generators(self): @@ -1123,3 +1140,525 @@ def _act_(self, g, x): D = {y: c for (y, dy), c in f.monomial_coefficients(copy=False).items() if all(dyi == 0 for dyi in dy)} return self.right_domain()(D) + + +class InfGenDifferentialWeylAlgebraElement(IndexedFreeModuleElement): + """ + An element of an infinitely generated differential Weyl algebra. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W.inject_variables(verbose=False) + sage: W.zero() == 0 + True + sage: W.one() == 1 + True + sage: W.zero() == 1 + False + sage: x[1] == 1 + False + sage: W(x[1]) == x[1] + True + sage: W(dx[1]) == dx[1] + True + sage: W(x[1] + dx[2]^2) == x[1] + dx[2]^2 + True + sage: x[1] == x[11] + False + sage: x[1] / 2 + 1/2*x[1] + sage: W(2) / 2 + 1 + sage: (x[1] + dx[1]) * (-4/3) + -4/3*dx[1] - 4/3*x[1] + sage: (-4/3) * (x[1] + dx[1]) + -4/3*dx[1] - 4/3*x[1] + """ + def _repr_(self) -> str: + """ + Return a string representation of ``self``. + + TESTS:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: dx = W.differentials() + sage: dx[1]^2*x[1]^2 + x[1]^2*dx[1]^2 + 4*x[1]*dx[1] + 2 + """ + def term(m): + res = '' + if not m[0].is_one(): + res += m[0]._repr_() + if not m[1].is_one(): + if res != '': + res += '*' + res += m[1]._repr_() + return res if res != '' else '1' + return repr_from_monomials(self.list(), term) + + def _mul_(self, other): + """ + Multiply ``self`` by ``other``. + + TESTS:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: dx = W.differentials() + sage: dx[1]*(x[1]*x[2] + x[3]) + x[1]*x[2]*dx[1] + x[3]*dx[1] + x[2] + sage: dx[132]*x[132] - x[132]*dx[132] == 1 + True + """ + out = {} + zero = self.parent().base_ring().zero() + zero_m = self.parent()._diff_index.one() + # multiply each pair of monomials + for ml in self._monomial_coefficients: + cl = self._monomial_coefficients[ml] + for mr in other._monomial_coefficients: + cr = other._monomial_coefficients[mr] + # apply derivative terms of ml to mr and simplify + cur = [((mr[0], zero_m), cl*cr)] + ldd = ml[1].dict() + + for i in ldd: + p = ldd[i] + # applying dx[i] p times + for _ in range(p): + next = [] + for m, c in cur: + diff = m[1].dict() + diff[i] = diff.get(i, zero) + 1 + next.append(((m[0], self.parent()._diff_index(diff)), c)) + # power rule if m has x[i] term + poly = m[0].dict() + if i in poly: + c *= poly[i] + poly[i] -= 1 + next.append(((self.parent()._var_index(poly), m[1]), c)) + cur = next + + for m, c in cur: + m = (ml[0] * m[0], m[1] * mr[1]) + out[m] = out.get(m, zero) + c + if out[m] == zero: + del out[m] + return self.__class__(self.parent(), out) + + def __iter__(self): + """ + Return an iterator of ``self``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ,n=oo) + sage: dx = W.differentials() + sage: p = x[5] + dx[1]*x[1] + sage: list(p) + [((x[1], dx[1]), 1), ((x[5], 1), 1), ((1, 1), 1)] + """ + return iter(self.list()) + + def list(self): + """ + Return ``self`` as a list. + + This list consists of pairs `(m, c)` where `m` is a pair of + :class:`IndexedFreeAbelianMonoid` + elements indexing a basis element of ``self``, and `c` is the + corresponding (nonzero) coefficient. The list is sorted using graded lex + order on the differentials, followed by graded lex order on the + polynomial generators. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: dx = W.differentials() + sage: p = x[5] + dx[1]*x[1] + sage: p.list() + [((x[1], dx[1]), 1), ((x[5], 1), 1), ((1, 1), 1)] + """ + return sorted(self._monomial_coefficients.items(), + key=lambda x: (-x[0][1].length(), x[0][1], -x[0][0].length(), x[0][0])) + + +class InfGenDifferentialWeylAlgebra(UniqueRepresentation, Parent): + r""" + The differential Weyl algebra of the polynomial ring in countably many + variables. + + Let `R` be a commutative ring, and `\{x_i\}` a countable family of + indeterminants. The differential Weyl algebra `W` is an `R`-algebra + generated by symbols `x_i`, and `\partial_{x_i}`, subject to the relations + `[x_i,x_j] = [\partial_{x_i}, \partial_{x_j}] = 0`, and + `[\partial_{x_i}, x_j] = \delta_{ij}`. + + INPUT: + + - ``R`` -- a commutative ring + - ``names`` -- length 1 tuple of strings denoting the prefix + for the variable names + + EXAMPLES: + + We construct an infinite Weyl algebra by using ``n=oo`` in + :class:`DifferentialWeylAlgebra`:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo); W + Differential Weyl algebra in countably many variables y over Rational Field + + Alternatively, one can first define an + :class:`InfinitePolynomialRing`` + and then define the differential Weyl algebra of that ring:: + + sage: R. = InfinitePolynomialRing(QQ) + sage: W = DifferentialWeylAlgebra(R); W + Differential Weyl algebra in countably many variables x over Rational Field + + .. WARNING:: + + Due to a bug in ``InfinitePolynomialRing`` (:issue:`36788`) trying to define the infinite Weyl + algebra of an infinite polynomial ring with coefficients in another infinite + polynomial ring will result in unexpected behavior:: + + sage: R. = InfinitePolynomialRing(QQ) + sage: R2. = InfinitePolynomialRing(R) + sage: W = DifferentialWeylAlgebra(R2); W # known bug + Differential Weyl algebra in countably many variables y over Infinite + polynomial ring in x over Rational Field + + + To access the variables, we can call ``W.inject_variables()``. The symbols + defined are families that allow you to access the `i`'th polynomial or differential + generator for each nonnegative integer `i`. Alternatively, we can access the families + directly using the :meth:`polynomial_gens` and :meth:`differentials` methods + respectively:: + + sage: W.inject_variables() + Defining x, dx + sage: dx + Lazy family (dx(i))_{i in Non negative integers} + sage: dx[1]*x[1] - x[1]*dx[1] + 1 + sage: (dx[1] + x[1]*dx[2])*(x[5]*dx[1] + 1) + x[5]*dx[1]^2 + x[1]*x[5]*dx[1]*dx[2] + dx[1] + x[1]*dx[2] + + TESTS:: + + sage: R1. = InfinitePolynomialRing(QQ) + sage: W = DifferentialWeylAlgebra(R1['y']); W + Differential Weyl algebra of polynomials in y over Infinite polynomial + ring in x over Rational Field + sage: W.inject_variables(verbose=False); R1.inject_variables(verbose=False) + sage: dy*x[1]*y + x_1*y*dy + x_1 + sage: R2. = InfinitePolynomialRing(QQ['y']) + sage: W = DifferentialWeylAlgebra(R2); W + Differential Weyl algebra in countably many variables x over Univariate + Polynomial Ring in y over Rational Field + sage: W.differential(1)*R2.base_ring()('y')*W.gen(1) + y*x[1]*dx[1] + y + """ + @staticmethod + def __classcall_private__(cls, R, names=None): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: W1. = DifferentialWeylAlgebra(QQ, n=oo) + sage: R = InfinitePolynomialRing(QQ) + sage: W2 = DifferentialWeylAlgebra(R, n=oo) + sage: W1 is W2 + True + """ + if isinstance(R, InfinitePolynomialRing_dense) and names is None: + names = R.variable_names() + if len(names) > 1: + raise NotImplementedError("only one set of variables supported") + R = R.base_ring() + if R not in Rings().Commutative(): + raise TypeError("argument R must be a commutative ring") + return super().__classcall__(cls, R, tuple(names)) + + def __init__(self, R, names=None): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: R = InfinitePolynomialRing(QQ) + sage: W = DifferentialWeylAlgebra(R, n=oo) + sage: W.inject_variables() + Defining x, dx + sage: TestSuite(W).run() + """ + from sage.categories.algebras_with_basis import AlgebrasWithBasis + from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid + from sage.sets.non_negative_integers import NonNegativeIntegers + + names = (names[0], 'd' + names[0]) + # could probably get away with only using one copy, but the distinction is nice + self._var_index = IndexedFreeAbelianMonoid(NonNegativeIntegers(), prefix=names[0]) + self._diff_index = IndexedFreeAbelianMonoid(NonNegativeIntegers(), prefix=names[1]) + if R.is_field(): + cat = AlgebrasWithBasis(R).NoZeroDivisors().Super() + else: + cat = AlgebrasWithBasis(R).Super() + Parent.__init__(self, base=R, names=names, category=cat) + + def _repr_(self) -> str: + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo); W + Differential Weyl algebra in countably many variables x over Rational Field + """ + return f"Differential Weyl algebra in countably many variables {self.variable_names()[0]} over {self.base_ring()}" + + def _element_constructor_(self, x): + """ + Construct an element of ``self`` from ``x``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W(1) + 1 + sage: a = W(x[1]); a.parent() is W + True + sage: R. = InfinitePolynomialRing(QQ) + sage: W(x[0]^2 + x[1]*x[3] + x[2]) + x[0]^2 + x[1]*x[3] + x[2] + """ + R = self.base_ring() + if x in R: + if x == self.base_ring().zero(): + return self.zero() + return self.element_class(self, {(self._var_index.one(), self._diff_index.one()): x}) + + if isinstance(x, InfinitePolynomial): + if x.parent().base_ring() is R: + return self.element_class(self, { + (prod(self._var_index.gen(len(m)-i-1)**m[i] for i in range(len(m))), + self._diff_index.one()): R(c) for m, c in x.monomial_coefficients().items() + }) + if isinstance(x, InfGenDifferentialWeylAlgebraElement): + if x.parent().base_ring() is R: + return self.element_class(self, dict(x)) + # attempt to coerce coefficients to R + zero = R.zero() + return self.element_class(self, {m: R(c) for m, c in x if R(c) != zero}) + + return self.element_class(self, + {(self._var_index(m[0]), + self._diff_index(m[1])): R(c) + for m, c in x.items()}) + + def _coerce_map_from_(self, R): + """ + Return data which determines if there is a coercion map + from ``R`` to ``self``. + + If such a map exists, the output could be a map, callable, + or ``True``, which constructs a generic map. Otherwise the output + must be ``False`` or ``None``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: dx = W.differentials() + sage: W2. = DifferentialWeylAlgebra(ZZ, n=oo) + sage: W._coerce_map_from_(W2) + True + sage: W3. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W._coerce_map_from_(W3) + False + sage: R. = InfinitePolynomialRing(QQ) + sage: W._coerce_map_from_(R) + True + sage: dx[1]*R(x[1]) + x[1]*dx[1] + 1 + """ + if isinstance(R, InfGenDifferentialWeylAlgebra): + return (self.variable_names() == R.variable_names() + and self.base_ring().has_coerce_map_from(R.base_ring())) + + if isinstance(R, InfinitePolynomialRing_dense): + return (self.variable_names()[:-1] == R.variable_names() + and self.base_ring().has_coerce_map_from(R.base_ring())) + + return super()._coerce_map_from_(R) + + def gen(self, i): + r""" + Return the ``i``-th polynomial generator of ``self``. + + INPUT: + + - ``i`` -- nonnegative integer + + OUTPUT: The polynomial generator `x_i` + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W.gen(1) + x[1] + sage: W.gen(1) == x[1] + True + """ + return self.element_class(self, {(self._var_index.gen(i), + self._diff_index.one()): self.base_ring().one()}) + + @cached_method + def polynomial_gens(self): + r""" + Return the polynomial generators of ``self``. + + OUTPUT: A (lazy) family containing the polynomial generators `x_i`. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: x = W.polynomial_gens(); x + Lazy family (x(i))_{i in Non negative integers} + sage: x[3] == W.gen(3) + True + """ + from sage.sets.non_negative_integers import NonNegativeIntegers + return Family(NonNegativeIntegers(), lambda x: self.gen(x), name=self.variable_names()[0]) + + @cached_method + def gens(self): + """ + Return the algebra generators of ``self``. + + OUTPUT: an ordered pair (x, dx) containing families indexing each set + of generators. + + EXAMPLES:: + + sage: R = InfinitePolynomialRing(QQ) + sage: W = DifferentialWeylAlgebra(R, n=oo) + sage: x, dx = W.gens() + """ + return (self.polynomial_gens(), self.differentials()) + + def differential(self, i): + r""" + Return the ``i``-th differential of ``self``. + + INPUT: + + - ``i`` -- nonnegative integer + + OUTPUT: The differential generator `\partial_{x_i}` + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W.inject_variables() + Defining x, dx + sage: W.differential(1) + dx[1] + sage: W.differential(1) == dx[1] + True + """ + return self.element_class(self, {(self._var_index.one(), + self._diff_index.gen(i)): self.base_ring().one()}) + + @cached_method + def differentials(self): + r""" + Return the differential generators of ``self``. + + OUTPUT: A (lazy) family containing the differential generators `\partial_{x_i}` + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: dx = W.differentials(); dx + Lazy family (dx(i))_{i in Non negative integers} + sage: dx[3] == W.differential(3) + True + """ + from sage.sets.non_negative_integers import NonNegativeIntegers + return Family(NonNegativeIntegers(), lambda x: self.differential(x), name=self.variable_names()[1]) + + @cached_method + def zero(self): + """ + Return the additive identity element `0` of ``self``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: x[1] + W.zero() == x[1] + True + sage: x[1]*W.zero() == W.zero() + True + """ + return self.element_class(self, {}) + + @cached_method + def one_basis(self): + """ + Return the multiplicative identity element `1` of ``self``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W.one_basis() == W.one().leading_support() + True + sage: x[1]*W.one() == x[1] + True + """ + return (self._var_index.one(), self._diff_index.one()) + + @cached_method + def basis(self): + """ + Return a basis for ``self``. + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: B = W.basis(); B + Lazy family (basis map(i))_{i in The Cartesian product of + (Free abelian monoid indexed by Non negative integers, + Free abelian monoid indexed by Non negative integers)} + sage: idx = W._var_index + sage: B[(idx.an_element(), idx.one())] + x[0]*x[1]^2*x[2]^3*x[42] + """ + index_set = cartesian_product([self._var_index, self._diff_index]) + one = self.base_ring().one() + return Family(index_set, + lambda x: self.element_class(self, {(x[0], x[1]): one}), + name='basis map') + + def degree_on_basis(self, x): + """ + Return the degree of basis element indexed by ``x``. This is the total + degree of the polynomial and differential parts of ``x``. + + INPUT: + + - ``x`` -- an index for a basis element + + OUTPUT: A nonnegative integer + + EXAMPLES:: + + sage: W. = DifferentialWeylAlgebra(QQ, n=oo) + sage: W.inject_variables(verbose=False); + sage: f = x[2]*x[3]*dx[1]^2; f.degree() + 4 + """ + return x[0].length() + x[1].length() + + Element = InfGenDifferentialWeylAlgebraElement diff --git a/src/sage/arith/functions.pyi b/src/sage/arith/functions.pyi new file mode 100644 index 00000000000..12d6c16164d --- /dev/null +++ b/src/sage/arith/functions.pyi @@ -0,0 +1,6 @@ +from collections.abc import Iterable +from typing import Any + +def lcm(a: Any, b: Any = None) -> Any: ... +def LCM_list(v: Iterable[Any]) -> Any: ... +def LCM_generic(itr: Iterable[Any], ret: Any) -> Any: ... diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index bad8695cb06..f0ca76fe42d 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -2236,9 +2236,9 @@ def get_gcd(order): EXAMPLES:: sage: sage.arith.misc.get_gcd(4000) - + sage: sage.arith.misc.get_gcd(400000) - + sage: sage.arith.misc.get_gcd(4000000000) """ @@ -2258,9 +2258,9 @@ def get_inverse_mod(order): EXAMPLES:: sage: sage.arith.misc.get_inverse_mod(6000) - + sage: sage.arith.misc.get_inverse_mod(600000) - + sage: sage.arith.misc.get_inverse_mod(6000000000) """ diff --git a/src/sage/arith/rational_reconstruction.pyi b/src/sage/arith/rational_reconstruction.pyi new file mode 100644 index 00000000000..e0a3e0239a8 --- /dev/null +++ b/src/sage/arith/rational_reconstruction.pyi @@ -0,0 +1,3 @@ +from typing import Any + +def mpq_rational_reconstruction(answer: Any, a: Any, m: Any) -> int: ... diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 5a075ae38b1..d41bf946a09 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1243,8 +1243,8 @@ def limit(ex, *args, dir=None, taylor=False, algorithm='maxima', **kwargs): sage: limit(sin(x)/x, x, 0, algorithm='sympy') 1 - sage: limit(abs(x)/x, x, 0, algorithm='giac') # needs sage.libs.giac # Two-sided limit -> undefined - und + sage: limit(sin(x)/x, x, 0, algorithm='giac') # needs sage.libs.giac + 1 sage: limit(x^x, x, 0, dir='+', algorithm='fricas') # optional - fricas 1 diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index ddcdf6bb44d..5d3f3fb0ce4 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -923,7 +923,7 @@ def latex_file(self, filename): Export a file, suitable for pdflatex, to ``filename``. This requires - a proper installation of ``dot2tex`` in sage-python. For more + a proper installation of ``dot2tex``. For more information see the documentation for ``self.latex()``. EXAMPLES:: diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 0f7ec03001a..b55bce25c6d 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -769,7 +769,8 @@ def base_ring(self): This ``base_ring`` method is actually overridden by :meth:`sage.structure.category_object.CategoryObject.base_ring`:: - sage: H.base_ring.__module__ # needs sage.modules + sage: H.base_ring.__module__ + 'sage.structure.category_object' Here we call it directly:: diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index dbae2b41049..d2a8786e201 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -931,6 +931,7 @@ class SubcategoryMethods: to use Sage's introspection tools to recover where it's implemented:: sage: x._repr_.__module__ + 'sage.structure.element_wrapper' sage: sage.misc.sageinspect.sage_getfile(x._repr_) '.../sage/structure/element_wrapper.pyx' diff --git a/src/sage/cli/notebook_cmd_test.py b/src/sage/cli/notebook_cmd_test.py index e1b9a0e880a..f576b0f358b 100644 --- a/src/sage/cli/notebook_cmd_test.py +++ b/src/sage/cli/notebook_cmd_test.py @@ -34,6 +34,6 @@ def test_invalid_notebook_choice(): def test_help(): - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser(prog="sage") JupyterNotebookCmd.extend_parser(parser) - assert parser.format_usage() == "usage: pytest [-h] [-n [{jupyter,jupyterlab}]]\n" + assert parser.format_usage() == "usage: sage [-h] [-n [{jupyter,jupyterlab}]]\n" diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index d016f3495ea..26b6ec2d07e 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -1017,9 +1017,6 @@ cdef class dancing_linksWrapper: the `i`-th row is in the solution:: sage: p.show() # needs sage.numerical.mip - Maximization: - - Constraints:... one 1 in 0-th column: 1.0 <= x_0 + x_1 <= 1.0 one 1 in 1-th column: 1.0 <= x_0 + x_2 <= 1.0 diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index 59dadb57199..6aebcfba965 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -2587,6 +2587,8 @@ class RuleStar(Rule): sage: FC_tabs = [T for shape in shapes ....: for T in SemistandardTableaux(shape, max_entry=4) ....: if fc(row_reading(T.conjugate()))] + sage: from random import sample + sage: FC_tabs = sample(FC_tabs, 25) # verify only a random subset sage: Checks = [] sage: for T in FC_tabs: # long time ....: shape = T.shape().conjugate() diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index 8345c4ebfac..1ef4a0d2fe3 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -43,7 +43,7 @@ def init(): sage: sage.combinat.sf.classical.conversion_functions = {} sage: init() sage: sage.combinat.sf.classical.conversion_functions[('Schur', 'powersum')] - + The following checks if the bug described in :issue:`15312` is fixed. :: diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index c97d512465a..54945b86cdd 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -155,8 +155,9 @@ class DES(SageObject): TESTS: - Test test vectors from [KeSm1998]_ pp. 125-136:: + Test a random subset of the test vectors in [KeSm1998]_ pp. 125-136:: + sage: # long time sage: from sage.crypto.block_cipher.des import DES sage: test = \ ....: [[0x0101010101010101, 0x8000000000000000, 0x95F8A5E5DD31D900], @@ -331,10 +332,10 @@ class DES(SageObject): ....: [0x018310DC409B26D6, 0x1D9D5C5018F728C2, 0x5F4C038ED12B2E41], ....: [0x1C587F1C13924FEF, 0x305532286D6F295A, 0x63FAC0D034D9F793]] sage: des = DES() - sage: for K, P, C in test: # long time - ....: if des.encrypt(P, K) != C or des.decrypt(C, K) != P: - ....: print("DES tests failed for K=0x%s, P=0x%s, C=0x%s" % - ....: (K.hex(), P.hex(), C.hex())) + sage: from random import sample + sage: all( des.encrypt(P,K) == C and des.decrypt(C,K) == P + ....: for (K,P,C) in sample(test,5) ) + True .. automethod:: __init__ .. automethod:: __call__ @@ -652,7 +653,7 @@ def _f(self, right, subkey): (0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1) """ - return self._permutaion(self.sbox_layer(self._expand(right)+subkey)) + return self._permutation(self.sbox_layer(self._expand(right)+subkey)) def _expand(self, right): r""" @@ -704,7 +705,7 @@ def sbox_layer(self, block): for i, b in enumerate(block)])) return vector(GF(2), 32, block) - def _permutaion(self, block): + def _permutation(self, block): r""" Apply the permutation function to ``block``. @@ -714,7 +715,7 @@ def _permutaion(self, block): sage: des = DES() sage: B = vector(GF(2), 32, [0,1,0,1,1,1,0,0,1,0,0,0,0,0,1,0,1,0,1, ....: 1,0,1,0,1,1,0,0,1,0,1,1,1]) - sage: des._permutaion(B) + sage: des._permutation(B) (0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1) """ diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py index 2602f439762..42d41eee574 100644 --- a/src/sage/doctest/test.py +++ b/src/sage/doctest/test.py @@ -50,7 +50,7 @@ Check slow doctest warnings are correctly raised:: - sage: subprocess.call(["sage", "-t", "--warn-long", # long time + sage: subprocess.call(["python3", "-m", "sage.doctest", "--warn-long", # long time ....: "--random-seed=0", "--optional=sage", "sleep2.rst"], **kwds) Running doctests... Doctesting 1 file. @@ -67,7 +67,7 @@ ---------------------------------------------------------------------- ... 0 - sage: subprocess.call(["sage", "-t", "--format=github", "--warn-long", # long time + sage: subprocess.call(["python3", "-m", "sage.doctest", "--format=github", "--warn-long", # long time ....: "--random-seed=0", "--optional=sage", "sleep2.rst"], **kwds) Running doctests... Doctesting 1 file. diff --git a/src/sage/env.py b/src/sage/env.py index c83b8b98b7a..078801b6109 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -234,6 +234,7 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st PPLPY_DOCS = var("PPLPY_DOCS", join(SAGE_SHARE, "doc", "pplpy")) MAXIMA = var("MAXIMA", "maxima") MAXIMA_FAS = var("MAXIMA_FAS") +MAXIMA_SHARE = var("MAXIMA_SHARE") KENZO_FAS = var("KENZO_FAS") SAGE_NAUTY_BINS_PREFIX = var("SAGE_NAUTY_BINS_PREFIX", "") SAGE_ECMBIN = var("SAGE_ECMBIN", "ecm") diff --git a/src/sage/ext_data/nbconvert/postprocess.py b/src/sage/ext_data/nbconvert/postprocess.py index 1774b9e1ca5..6a0d21f2d9c 100755 --- a/src/sage/ext_data/nbconvert/postprocess.py +++ b/src/sage/ext_data/nbconvert/postprocess.py @@ -1,4 +1,4 @@ -#!/usr/bin/env sage-python +#!/usr/bin/env python3 r""" This postprocess script fixes some issues with .rst files returned by nbconvert: diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 7d8aae5e823..9d9653cccd0 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -56,6 +56,7 @@ from sage.rings.integer cimport smallInteger from sage.rings.integer_ring import ZZ +from collections.abc import Iterable cdef extern from "Python.h": int unlikely(int) nogil # Defined by Cython @@ -3628,6 +3629,134 @@ cdef class CGraphBackend(GenericGraphBackend): return Infinity return [] + def shortest_path_to_set(self, source, targets, by_weight=False, edge_weight=None, + exclude_vertices=None, report_weight=False,): + r""" + Return the shortest path from ``source`` to any vertex in ``targets``. + + INPUT: + + - ``source`` -- the starting vertex. + + - ``targets`` -- iterable container; the set of end vertices. + + - ``edge_weight`` -- dictionary (default: ``None``); a dictionary + that takes as input an edge ``(u, v)`` and outputs its weight. + If not ``None``, ``by_weight`` is automatically set to ``True``. + If ``None`` and ``by_weight`` is ``True``, we use the edge + label ``l`` as a weight. + + - ``by_weight`` -- boolean (default: ``False``); if ``True``, the edges + in the graph are weighted, otherwise all edges have weight 1. + + - ``exclude_vertices`` -- iterable container (default: ``None``); + iterable of vertices to exclude from the graph while calculating the + shortest path from ``source`` to any vertex in ``targets``. + + - ``report_weight`` -- boolean (default: ``False``); if ``False``, just + a path is returned. Otherwise a tuple of path length and path is + returned. + + OUTPUT: + + - A list of vertices in the shortest path from ``source`` to any vertex + in ``targets`` or a tuple of path lengh and path is returned + depending upon the value of parameter ``report_weight``. + + EXAMPLES:: + + sage: g = Graph([(1, 2, 10), (1, 3, 20), (1, 4, 30)]) + sage: g._backend.shortest_path_to_set(1, {3, 4}, by_weight=True) + [1, 3] + sage: g = Graph([(1, 2, 10), (2, 3, 10), (1, 4, 20), (4, 5, 20), (1, 6, 30), (6, 7, 30)]) + sage: g._backend.shortest_path_to_set(1, {5, 7}, by_weight=True, exclude_vertices=[4], report_weight=True) + (60.0, [1, 6, 7]) + + TESTS:: + + sage: g = Graph([(1, 2, 10), (1, 3, 20), (1, 4, 30)]) + sage: g._backend.shortest_path_to_set(1, {3, 4}, exclude_vertices=[3], by_weight=True) + [1, 4] + sage: g._backend.shortest_path_to_set(1, {1, 3, 4}, by_weight=True) + [1] + + ``source`` must not be in ``exclude_vertices``:: + + sage: g._backend.shortest_path_to_set(1, {3, 4}, exclude_vertices=[1]) + Traceback (most recent call last): + ... + ValueError: source must not be in exclude_vertices. + + When no path exists from ``source`` to ``targets``, raise an error. + + sage: g._backend.shortest_path_to_set(1, {3, 4}, exclude_vertices=[3, 4]) + Traceback (most recent call last): + ... + ValueError: no path found from source to targets. + + ``exclude_vertices`` must be iterable:: + + sage: g._backend.shortest_path_to_set(1, {1, 3, 4}, exclude_vertices=100) + Traceback (most recent call last): + ... + TypeError: exclude_vertices (100) are not iterable. + """ + if not exclude_vertices: + exclude_vertices = set() + elif not isinstance(exclude_vertices, Iterable): + raise TypeError(f"exclude_vertices ({exclude_vertices}) are not iterable.") + elif not isinstance(exclude_vertices, set): + exclude_vertices = set(exclude_vertices) + if source in exclude_vertices: + raise ValueError(f"source must not be in exclude_vertices.") + cdef PairingHeap[int, double] pq = PairingHeap[int, double]() + cdef dict dist = {} + cdef dict pred = {} + cdef int x_int = self.get_vertex(source) + pq.push(x_int, 0) + dist[x_int] = 0 + + while not pq.empty(): + v_int, d = pq.top() + pq.pop() + v = self.vertex_label(v_int) + + if v in targets: + # found a vertex in targets + path = [] + while v_int in pred: + path.append(self.vertex_label(v_int)) + v_int = pred[v_int] + path.append(source) + path.reverse() + return (d, path) if report_weight else path + + if d > dist.get(v_int, float('inf')): + continue # already found a better path + + for _, u, label in self.iterator_out_edges([v], labels=True): + if u in exclude_vertices: + continue + if edge_weight: + e_weight = edge_weight[(v, u)] + elif by_weight: + e_weight = label + else: + e_weight = 1 + new_dist = d + e_weight + u_int = self.get_vertex(u) + if new_dist < dist.get(u_int, float('inf')): + dist[u_int] = new_dist + pred[u_int] = v_int + if pq.contains(u_int): + if pq.value(u_int) > new_dist: + pq.decrease(u_int, new_dist) + else: + pq.push(u_int, new_dist) + + # no path found + raise ValueError(f"no path found from source to targets.") + def bidirectional_dijkstra_special(self, x, y, weight_function=None, exclude_vertices=None, exclude_edges=None, include_vertices=None, distance_flag=False, diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index f4464fcbf8c..7e1fe6cab1b 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -1509,42 +1509,6 @@ cdef class StaticSparseBackend(CGraphBackend): yield self._vertex_to_labels[u] seen.add(u) - def add_vertex(self, v): - r""" - Addition of vertices is not available on an immutable graph. - - EXAMPLES:: - - sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse') - sage: g.add_vertex(1) - Traceback (most recent call last): - ... - TypeError: this graph is immutable and so cannot be changed - sage: g.add_vertices([1,2,3]) - Traceback (most recent call last): - ... - TypeError: this graph is immutable and so cannot be changed - """ - ( self._cg).add_vertex(v) - - def del_vertex(self, v): - r""" - Removal of vertices is not available on an immutable graph. - - EXAMPLES:: - - sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse') - sage: g.delete_vertex(1) - Traceback (most recent call last): - ... - TypeError: this graph is immutable and so cannot be changed - sage: g.delete_vertices([1,2,3]) - Traceback (most recent call last): - ... - TypeError: this graph is immutable and so cannot be changed - """ - ( self._cg).del_vertex(v) - @cython.binding(True) def _run_it_on_static_instead(f): diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 4992f46c877..ac1b4391eeb 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -3177,8 +3177,8 @@ def p2_forbidden_minors(): TESTS:: - sage: len(graphs.families.p2_forbidden_minors()) - 35 + sage: len(graphs.families.p2_forbidden_minors()) + 35 """ p2_forbidden_minors_graph6 = [ @@ -3221,6 +3221,7 @@ def p2_forbidden_minors(): return [Graph(graph_str) for graph_str in p2_forbidden_minors_graph6] + def SierpinskiGasketGraph(n): """ Return the Sierpinski Gasket graph of generation `n`. diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index bb51e293fab..76a42572244 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -9584,7 +9584,6 @@ def is_projective_planar(self, return_map=False): return True - # Aliases to functions defined in other modules from sage.graphs.weakly_chordal import is_long_hole_free, is_long_antihole_free, is_weakly_chordal from sage.graphs.asteroidal_triples import is_asteroidal_triple_free diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index a592d0c9b54..34431100807 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -36,7 +36,11 @@ from itertools import product from sage.misc.misc_c import prod from libcpp.queue cimport priority_queue from libcpp.pair cimport pair +from libcpp.vector cimport vector + +from sage.data_structures.pairing_heap cimport PairingHeap from sage.rings.integer_ring import ZZ + import copy @@ -1515,49 +1519,56 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None, G.delete_edges(G.incoming_edges(source, labels=False)) G.delete_edges(G.outgoing_edges(target, labels=False)) + # relabel the graph so that vertices are named with integers + cdef list int_to_vertex = list(G) + cdef dict vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} + G.relabel(perm=vertex_to_int, inplace=True) + cdef int id_source = vertex_to_int[source] + cdef int id_target = vertex_to_int[target] + + def relabeled_weight_function(e, wf=weight_function): + return wf((int_to_vertex[e[0]], int_to_vertex[e[1]], e[2])) + by_weight, weight_function = G._get_weight_function(by_weight=by_weight, - weight_function=weight_function, + weight_function=(relabeled_weight_function if weight_function else None), check_weight=check_weight) def reverse_weight_function(e): return weight_function((e[1], e[0], e[2])) - cdef dict edge_labels - edge_labels = {(e[0], e[1]): e for e in G.edge_iterator()} - - cdef dict edge_wt - edge_wt = {(e[0], e[1]): weight_function(e) for e in G.edge_iterator()} + cdef dict original_edge_labels = {(u, v): (int_to_vertex[u], int_to_vertex[v], label) + for u, v, label in G.edge_iterator()} + cdef dict original_edges = {(u, v): (int_to_vertex[u], int_to_vertex[v]) + for u, v in G.edge_iterator(labels=False)} + cdef dict edge_wt = {(e[0], e[1]): weight_function(e) for e in G.edge_iterator()} # The first shortest path tree T_0 from sage.graphs.base.boost_graph import shortest_paths cdef dict dist cdef dict successor reverse_graph = G.reverse() - dist, successor = shortest_paths(reverse_graph, target, weight_function=reverse_weight_function, + dist, successor = shortest_paths(reverse_graph, id_target, weight_function=reverse_weight_function, algorithm='Dijkstra_Boost') cdef set unnecessary_vertices = set(G) - set(dist) # no path to target - if source in unnecessary_vertices: # no path from source to target + if id_source in unnecessary_vertices: # no path from source to target return + G.delete_vertices(unnecessary_vertices) # sidetrack cost cdef dict sidetrack_cost = {(e[0], e[1]): weight_function(e) + dist[e[1]] - dist[e[0]] - for e in G.edge_iterator() - if e[0] in dist and e[1] in dist} - - def sidetrack_length(path): - return sum(sidetrack_cost[e] for e in zip(path, path[1:])) + for e in G.edge_iterator() if e[0] in dist and e[1] in dist} # v-t path in the first shortest path tree T_0 def tree_path(v): path = [v] - while v != target: + while v != id_target: v = successor[v] path.append(v) return path # shortest path - shortest_path = tree_path(source) - cdef double shortest_path_length = dist[source] + shortest_path = tree_path(id_source) + cdef double shortest_path_length = dist[id_source] # idx of paths cdef dict idx_to_path = {0: shortest_path} @@ -1568,9 +1579,66 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None, # (i.e. real length = cost + shortest_path_length in T_0) cdef priority_queue[pair[pair[double, bint], pair[int, int]]] candidate_paths - # shortest path function for weighted/unweighted graph using reduced weights - shortest_path_func = G._backend.bidirectional_dijkstra_special + # ancestor_idx_vec[v] := the first vertex of ``path[:t+1]`` or ``id_target`` reachable by + # edges of first shortest path tree from v. + cdef vector[int] ancestor_idx_vec = [-1 for _ in range(len(G))] + + def ancestor_idx_func(v, t, target_idx): + if ancestor_idx_vec[v] != -1: + if ancestor_idx_vec[v] <= t or ancestor_idx_vec[v] == target_idx: + return ancestor_idx_vec[v] + ancestor_idx_vec[v] = ancestor_idx_func(successor[v], t, target_idx) + return ancestor_idx_vec[v] + + # used inside shortest_path_to_green + cdef PairingHeap[int, double] pq = PairingHeap[int, double]() + cdef dict dist_in_func = {} + cdef dict pred = {} + + # calculate shortest path from dev to one of green vertices + def shortest_path_to_green(dev, exclude_vertices): + t = len(exclude_vertices) + ancestor_idx_vec[id_target] = t + 1 + # clear + while not pq.empty(): + pq.pop() + dist_in_func.clear() + pred.clear() + + pq.push(dev, 0) + dist_in_func[dev] = 0 + + while not pq.empty(): + v, d = pq.top() + pq.pop() + + if ancestor_idx_func(v, t, t + 1) == t + 1: # green + path = [] + while v in pred: + path.append(v) + v = pred[v] + path.append(dev) + path.reverse() + return (d, path) + + if d > dist_in_func.get(v, float('inf')): + continue # already found a better path + + for u in G.neighbor_out_iterator(v): + if u in exclude_vertices: + continue + new_dist = d + sidetrack_cost[(v, u)] + if new_dist < dist_in_func.get(u, float('inf')): + dist_in_func[u] = new_dist + pred[u] = v + if pq.contains(u): + if pq.value(u) > new_dist: + pq.decrease(u, new_dist) + else: + pq.push(u, new_dist) + return + cdef int i, deviation_i candidate_paths.push(((0, True), (0, 0))) while candidate_paths.size(): (negative_cost, is_simple), (path_idx, dev_idx) = candidate_paths.top() @@ -1580,29 +1648,19 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None, path = idx_to_path[path_idx] del idx_to_path[path_idx] - # ancestor_idx_dict[v] := the first vertex of ``path[:t+1]`` or ``path[-1]`` reachable by - # edges of first shortest path tree from v when enumerating deviating edges - # from ``path[t]``. - ancestor_idx_dict = {v: i for i, v in enumerate(path)} - - def ancestor_idx_func(v, t, len_path): - if v not in successor: - # target vertex is not reachable from v - return -1 - if v in ancestor_idx_dict: - if ancestor_idx_dict[v] <= t or ancestor_idx_dict[v] == len_path - 1: - return ancestor_idx_dict[v] - ancestor_idx_dict[v] = ancestor_idx_func(successor[v], t, len_path) - return ancestor_idx_dict[v] + for i in range(ancestor_idx_vec.size()): + ancestor_idx_vec[i] = -1 + for i, v in enumerate(path): + ancestor_idx_vec[v] = i if is_simple: # output if report_edges and labels: - P = [edge_labels[e] for e in zip(path, path[1:])] + P = [original_edge_labels[e] for e in zip(path, path[1:])] elif report_edges: - P = list(zip(path, path[1:])) + P = [original_edges[e] for e in zip(path, path[1:])] else: - P = path + P = [int_to_vertex[v] for v in path] if report_weight: yield (shortest_path_length + cost, P) else: @@ -1610,35 +1668,34 @@ def pnc_k_shortest_simple_paths(self, source, target, weight_function=None, # GET DEVIATION PATHS original_cost = cost - for deviation_i in range(len(path) - 1, dev_idx - 1, -1): + former_part = set(path) + for deviation_i in range(len(path) - 2, dev_idx - 1, -1): for e in G.outgoing_edge_iterator(path[deviation_i]): - if e[1] in path[:deviation_i + 2]: # e[1] is red or e in path - continue - ancestor_idx = ancestor_idx_func(e[1], deviation_i, len(path)) - if ancestor_idx == -1: + if e[1] in former_part: # e[1] is red or e in path continue - new_path = path[:deviation_i + 1] + tree_path(e[1]) + ancestor_idx = ancestor_idx_func(e[1], deviation_i, len(path) - 1) + new_is_simple = ancestor_idx > deviation_i + # no need to compute tree_path if new_is_simple is False + new_path = path[:deviation_i + 1] + (tree_path(e[1]) if new_is_simple else [e[1]]) new_path_idx = idx idx_to_path[new_path_idx] = new_path idx += 1 new_cost = original_cost + sidetrack_cost[(e[0], e[1])] - new_is_simple = ancestor_idx > deviation_i candidate_paths.push(((-new_cost, new_is_simple), (new_path_idx, deviation_i + 1))) if deviation_i == dev_idx: continue original_cost -= sidetrack_cost[(path[deviation_i - 1], path[deviation_i])] + former_part.remove(path[deviation_i + 1]) else: - # get a path to target in G \ path[:dev_idx] - deviation = shortest_path_func(path[dev_idx], target, - exclude_vertices=unnecessary_vertices.union(path[:dev_idx]), - reduced_weight=sidetrack_cost) - if not deviation: + deviations = shortest_path_to_green(path[dev_idx], set(path[:dev_idx])) + if not deviations: continue # no path to target in G \ path[:dev_idx] - new_path = path[:dev_idx] + deviation + deviation_weight, deviation = deviations + new_path = path[:dev_idx] + deviation[:-1] + tree_path(deviation[-1]) new_path_idx = idx idx_to_path[new_path_idx] = new_path idx += 1 - new_cost = sidetrack_length(new_path) + new_cost = cost + deviation_weight candidate_paths.push(((-new_cost, True), (new_path_idx, dev_idx))) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index a0946112787..b60a73b30e4 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1161,7 +1161,7 @@ def is_RSHCD(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_RSHCD sage: t = is_RSHCD(64,27,10,12); t # needs sage.combinat sage.modules - [, 64, 27, 10, 12] + [, 64, 27, 10, 12] sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index d20f209788f..bc3582107fa 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -532,3 +532,17 @@ def some_elements(self): vecs = self.vector_space().some_elements() return [self.element_class(self, A, b, check=False, convert=False) for A in mats for b in vecs] + + def __iter__(self): + """ + TESTS:: + + sage: G = AffineGroup(2, 3) + sage: len([g for g in G]) == G.cardinality() # indirect doctest + True + """ + for A in self._GL: + for b in self.vector_space(): + yield self.element_class(self, A, b, check=False, convert=False) + + __len__ = cardinality diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index c2633b534d7..36198c25797 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -3131,15 +3131,11 @@ def as_finitely_presented_group(self, reduced=False): sage: PermutationGroup([]).as_finitely_presented_group() Finitely presented group < a | a > - sage: S = SymmetricGroup(6) + sage: S = SymmetricGroup(4) sage: perm_ls = [S.random_element() for i in range(3)] sage: G = PermutationGroup(perm_ls) - sage: while True: - ....: try: - ....: assert G.as_finitely_presented_group().as_permutation_group().is_isomorphic(G) # sometimes results in GAP error (see :issue:`32141`) - ....: break - ....: except ValueError: - ....: pass + sage: G.as_finitely_presented_group().as_permutation_group().is_isomorphic(G) + True `D_9` is the only non-Abelian group of order 18 with an automorphism group of order 54 [TW1980]_:: diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index 4ad8fade90b..8899e2858b4 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -179,36 +179,49 @@ import os import re -import sage.interfaces.abc +from pexpect import EOF -from .expect import Expect, ExpectElement, FunctionElement, ExpectFunction +import sage.interfaces.abc from sage.env import DOT_SAGE -from pexpect import EOF -from sage.misc.multireplace import multiple_replace +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, +) from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc +from sage.misc.multireplace import multiple_replace from sage.structure.richcmp import rich_to_bool - # The Axiom commands ")what thing det" ")show Matrix" and ")display # op det" commands, gives a list of all identifiers that begin in # a certain way. This could maybe be useful somehow... (?) Also # axiom has a lot a lot of ways for getting documentation from the # system -- this could also be useful. + class PanAxiom(ExtraTabCompletion, Expect): """ Interface to a PanAxiom interpreter. """ - def __init__(self, name='axiom', command='axiom -nox -noclef', - script_subdirectory=None, logfile=None, - server=None, server_tmpdir=None, - init_code=[')lisp (si::readline-off)']): + + def __init__( + self, + name="axiom", + command="axiom -nox -noclef", + script_subdirectory=None, + logfile=None, + server=None, + server_tmpdir=None, + init_code=[")lisp (si::readline-off)"], + ): """ Create an instance of the Axiom interpreter. TESTS:: + sage: from sage.interfaces.axiom import axiom sage: axiom == loads(dumps(axiom)) True """ @@ -829,8 +842,8 @@ def _sage_(self): return self._sage_domain() if type == "Float": - from sage.rings.real_mpfr import RealField from sage.rings.integer_ring import ZZ + from sage.rings.real_mpfr import RealField prec = max(self.mantissa().length()._sage_(), 53) R = RealField(prec) x, e, b = self.unparsed_input_form().lstrip('float(').rstrip(')').split(',') diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index 5107f532adf..e028236c288 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -191,26 +191,31 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from .expect import Expect, ExpectElement, FunctionElement, ExpectFunction -from .gap_workspace import gap_workspace_file, prepare_workspace_dir -from sage.cpython.string import bytes_to_str -from sage.env import SAGE_EXTCODE, SAGE_GAP_COMMAND, SAGE_GAP_MEMORY, GAP_ROOT_PATHS -from sage.misc.misc import is_in_string -from sage.misc.cachefunc import cached_method -from sage.misc.instancedoc import instancedoc -from sage.interfaces.tab_completion import ExtraTabCompletion -from sage.structure.element import ModuleElement - -import sage.interfaces.abc - -import re import os -import pexpect -import time import platform +import re import string +import time import warnings +import pexpect + +import sage.interfaces.abc +from sage.cpython.string import bytes_to_str +from sage.env import GAP_ROOT_PATHS, SAGE_EXTCODE, SAGE_GAP_COMMAND, SAGE_GAP_MEMORY +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, +) +from sage.interfaces.gap_workspace import gap_workspace_file, prepare_workspace_dir +from sage.interfaces.tab_completion import ExtraTabCompletion +from sage.misc.cachefunc import cached_method +from sage.misc.instancedoc import instancedoc +from sage.misc.misc import is_in_string +from sage.structure.element import ModuleElement + WORKSPACE = gap_workspace_file() first_try = True @@ -893,10 +898,9 @@ def function_call(self, function, args=None, kwds=None): res = self.eval(cmd) if self.eval(self._identical_function + '(last,__SAGE_LAST__)') != 'true': return self.new('last2;') - else: - if res.strip(): - from sage.interfaces.interface import AsciiArtString - return AsciiArtString(res) + elif res.strip(): + from sage.interfaces.interface import AsciiArtString + return AsciiArtString(res) def get_record_element(self, record, name): r""" @@ -1072,6 +1076,7 @@ def __init__(self, max_workspace_size=None, """ EXAMPLES:: + sage: from sage.interfaces.gap import gap sage: gap == loads(dumps(gap)) True """ diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 85df9d2048f..b67055658ef 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -237,17 +237,21 @@ import os -from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled - import pexpect from sage.cpython.string import bytes_to_str from sage.env import DOT_SAGE -from sage.misc.pager import pager +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, + gc_disabled, +) from sage.misc.instancedoc import instancedoc +from sage.misc.pager import pager from sage.structure.richcmp import rich_to_bool - COMMANDS_CACHE = '%s/giac_commandlist_cache.sobj' % DOT_SAGE @@ -326,6 +330,7 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, server_t EXAMPLES:: + sage: from sage.interfaces.giac import giac sage: giac == loads(dumps(giac)) True """ @@ -1115,8 +1120,11 @@ def _sage_(self, locals=None): sage: giac(e * i * pi).sage().variables() () """ + from sage.calculus.calculus import ( + SR_parser_giac, + symbolic_expression_from_string, + ) from sage.symbolic.expression import symbol_table - from sage.calculus.calculus import symbolic_expression_from_string, SR_parser_giac if locals is None: locals = {} diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index e60db964e94..508fbc4e928 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -140,7 +140,6 @@ import os import sage.interfaces.abc - from sage.env import DOT_SAGE from sage.interfaces.tab_completion import ExtraTabCompletion from sage.libs.pari import pari @@ -210,6 +209,7 @@ def __init__(self, stacksize=10000000, # 10MB EXAMPLES:: + sage: from sage.interfaces.gp import gp sage: gp == loads(dumps(gp)) True """ diff --git a/src/sage/interfaces/lie.py b/src/sage/interfaces/lie.py index e89419e68f6..7e6ac4dcf14 100644 --- a/src/sage/interfaces/lie.py +++ b/src/sage/interfaces/lie.py @@ -285,17 +285,21 @@ # https://www.gnu.org/licenses/ # ########################################################################## -from itertools import chain import os +from itertools import chain -from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement -from sage.interfaces.interface import AsciiArtString -from sage.misc.misc_c import prod from sage.env import DOT_SAGE, LIE_INFO_DIR -from sage.misc.sage_eval import sage_eval +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, +) +from sage.interfaces.interface import AsciiArtString from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc - +from sage.misc.misc_c import prod +from sage.misc.sage_eval import sage_eval COMMANDS_CACHE = '%s/lie_commandlist_cache.sobj' % DOT_SAGE HELP_CACHE = '%s/lie_helpdict_cache.sobj' % DOT_SAGE @@ -319,6 +323,7 @@ def __init__(self, """ EXAMPLES:: + sage: from sage.interfaces.lie import lie sage: lie == loads(dumps(lie)) True """ diff --git a/src/sage/interfaces/lisp.py b/src/sage/interfaces/lisp.py index a324d7b76a8..e69534c1464 100644 --- a/src/sage/interfaces/lisp.py +++ b/src/sage/interfaces/lisp.py @@ -53,9 +53,15 @@ import os import random -from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled -from sage.structure.element import RingElement, parent +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, + gc_disabled, +) from sage.misc.instancedoc import instancedoc +from sage.structure.element import RingElement, parent from sage.structure.richcmp import rich_to_bool @@ -68,6 +74,7 @@ def __init__(self, """ EXAMPLES:: + sage: from sage.interfaces.lisp import lisp sage: lisp == loads(dumps(lisp)) True """ diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index da15f7c26e4..bfc7b67cdd4 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -126,14 +126,17 @@ import re import sage.interfaces.abc - -from sage.interfaces.expect import (Expect, ExpectElement, ExpectFunction, - FunctionElement) +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, +) from sage.interfaces.interface import AsciiArtString -from sage.misc.multireplace import multiple_replace -from sage.misc.superseded import deprecated_function_alias from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc +from sage.misc.multireplace import multiple_replace +from sage.misc.superseded import deprecated_function_alias from sage.structure.global_options import GlobalOptions @@ -202,6 +205,7 @@ def __init__(self, maxread=None, script_subdirectory=None, TESTS:: + sage: from sage.interfaces.macaulay2 import macaulay2 sage: macaulay2 == loads(dumps(macaulay2)) True """ @@ -1590,8 +1594,8 @@ def _sage_(self): # Handle the ZZ/n case ambient = self.ambient() if ambient.external_string() == 'ZZ': - from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF + from sage.rings.integer_ring import ZZ external_string = self.external_string() zz, n = external_string.split("/") @@ -1603,7 +1607,9 @@ def _sage_(self): ideal = self.ideal()._sage_() return ambient_ring.quotient(ideal, names=ambient_ring.variable_names()) elif cls_str == "PolynomialRing": - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import ( + PolynomialRing, + ) from sage.rings.polynomial.term_order import inv_macaulay2_name_mapping # Get the base ring @@ -1629,8 +1635,8 @@ def _sage_(self): return PolynomialRing(base_ring, order=order, names=gens) elif cls_str == "GaloisField": - from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF + from sage.rings.integer_ring import ZZ gf, n = repr_str.split(" ") n = ZZ(n) if n.is_prime(): diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index 5929582742e..132bd923713 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -237,17 +237,21 @@ import os -from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled - import pexpect +from sage.cpython.string import bytes_to_str from sage.env import DOT_SAGE -from sage.misc.pager import pager +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, + gc_disabled, +) from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc +from sage.misc.pager import pager from sage.structure.richcmp import rich_to_bool -from sage.cpython.string import bytes_to_str - COMMANDS_CACHE = '%s/maple_commandlist_cache.sobj' % DOT_SAGE @@ -270,6 +274,7 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, EXAMPLES:: + sage: from sage.interfaces.maple import maple sage: maple == loads(dumps(maple)) True """ diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index ba31f56aa4f..ebe00cd51e7 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -494,19 +494,20 @@ import os import re -import pexpect import shlex - from random import randrange -from sage.env import MAXIMA - -from .expect import (Expect, ExpectElement, gc_disabled) +import pexpect -from .maxima_abstract import (MaximaAbstract, MaximaAbstractFunction, - MaximaAbstractElement, - MaximaAbstractFunctionElement, - MaximaAbstractElementFunction) +from sage.env import MAXIMA +from sage.interfaces.expect import Expect, ExpectElement, gc_disabled +from sage.interfaces.maxima_abstract import ( + MaximaAbstract, + MaximaAbstractElement, + MaximaAbstractElementFunction, + MaximaAbstractFunction, + MaximaAbstractFunctionElement, +) from sage.misc.instancedoc import instancedoc @@ -529,6 +530,7 @@ def __init__(self, script_subdirectory=None, logfile=None, server=None, TESTS:: + sage:: from sage.interfaces.maxima import Maxima, maxima sage: Maxima == loads(dumps(Maxima)) True sage: maxima == loads(dumps(maxima)) diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 1d732ee7b52..0a6ae7d0dae 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -113,24 +113,24 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element import Expression -from sage.symbolic.ring import SR - -from sage.libs.ecl import EclObject, ecl_eval - -from .maxima_abstract import (MaximaAbstract, MaximaAbstractFunction, - MaximaAbstractElement, MaximaAbstractFunctionElement, - MaximaAbstractElementFunction) -from sage.misc.instancedoc import instancedoc -from sage.env import MAXIMA_FAS - import sage.rings.real_double import sage.symbolic.expression import sage.symbolic.integration.integral - +from sage.env import MAXIMA_FAS, MAXIMA_SHARE +from sage.libs.ecl import EclObject, ecl_eval +from sage.misc.instancedoc import instancedoc from sage.rings.number_field.number_field_element_base import NumberFieldElement_base +from sage.structure.element import Expression from sage.symbolic.operators import FDerivativeOperator, add_vararg, mul_vararg +from sage.symbolic.ring import SR +from .maxima_abstract import ( + MaximaAbstract, + MaximaAbstractElement, + MaximaAbstractElementFunction, + MaximaAbstractFunction, + MaximaAbstractFunctionElement, +) # We begin here by initializing Maxima in library mode # i.e. loading it into ECL @@ -205,6 +205,13 @@ ecl_eval("(setf *standard-output* *dev-null*)") # ecl_eval("(setf *error-output* *dev-null*)") +# Add search paths +# Keep these in sync with the default Maxima search paths defined in subprojects/maxima-/src/share-subdirs_autogenerated.lisp +if MAXIMA_SHARE: + import_packages = "{affine,algebra,algebra/charsets,algebra/solver,amatrix,bernstein,calculus,cobyla,cobyla/ex,cobyla/lisp,colnew,colnew/ex1,colnew/ex2,colnew/ex3,colnew/ex4,colnew/lisp,combinatorics,contrib,contrib/Eulix,contrib/Grobner,contrib/Zeilberger,contrib/alt-display,contrib/altsimp,contrib/binsplit,contrib/bitwise,contrib/boolsimp,contrib/coma,contrib/diffequations,contrib/diffequations/tests,contrib/elliptic_curves,contrib/elliptic_curves/figures,contrib/format,contrib/fresnel,contrib/gentran,contrib/gentran/man,contrib/gentran/test,contrib/gf,contrib/integration,contrib/levin,contrib/lurkmathml,contrib/maxima-odesolve,contrib/maximaMathML,contrib/mcclim,contrib/noninteractive,contrib/odes,contrib/operatingsystem,contrib/prim,contrib/rand,contrib/rkf45,contrib/sarag,contrib/smath,contrib/state,contrib/symplectic_ode,contrib/trigtools,contrib/unicodedata,contrib/unit,contrib/vector3d,descriptive,diff_form,diff_form/tests,diffequations,distrib,draw,dynamics,ezunits,fftpack5,fftpack5/lisp,finance,fourier_elim,fractals,graphs,hompack,hompack/lisp,hypergeometric,integequations,integer_sequence,integration,lapack,lapack/blas,lapack/lapack,lbfgs,linearalgebra,logic,lsquares,macro,matrix,minpack,minpack/lisp,misc,mnewton,multiadditive,nelder_mead,numeric,numericalio,odepack,odepack/src,orthopoly,pdiff,physics,pslq,pytranslate,quantum,simplex,simplex/Tests,simplification,solve_rat_ineq,solve_rec,sound,stats,stringproc,sym,tensor,tensor/tracefree-code,test_batch_encodings,to_poly_solve,translators,translators/m2mj,trigonometry,utils,vector,z_transform}" + ecl_eval(f'#$file_search_maxima: append(file_search_maxima, ["{MAXIMA_SHARE}/###.{{mac,mc,wxm}}", "{MAXIMA_SHARE}/{import_packages}/###.{{mac,mc,wxm}}"])$') + ecl_eval(f'#$file_search_lisp: append(file_search_lisp, ["{MAXIMA_SHARE}/###.{{fas,lisp,lsp}}", "{MAXIMA_SHARE}/{import_packages}/###.{{fas,lisp,lsp}}"])$') + # Default options set in Maxima # display2d -- no ascii art output # keepfloat -- don't automatically convert floats to rationals @@ -1567,7 +1574,9 @@ def pyobject_to_max(obj): if isinstance(obj, sage.rings.rational.Rational): return EclObject(obj) if (obj.denom().is_one()) else EclObject([[rat], obj.numer(), obj.denom()]) elif isinstance(obj, NumberFieldElement_base): - from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic + from sage.rings.number_field.number_field_element_quadratic import ( + NumberFieldElement_quadratic, + ) if isinstance(obj, NumberFieldElement_quadratic) and obj.parent().defining_polynomial().list() == [1, 0, 1]: re, im = obj.list() return EclObject([[mplus], pyobject_to_max(re), [[mtimes], pyobject_to_max(im), max_i]]) @@ -1680,6 +1689,7 @@ def sr_to_max(expr): # This goes from EclObject to SR from sage.symbolic.expression import symbol_table + max_to_pynac_table = symbol_table['maxima'] diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index da26ea800b5..059f61b2331 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -145,12 +145,14 @@ # **************************************************************************** import os -from .expect import Expect, ExpectElement + import pexpect -from sage.misc.verbose import verbose + +from sage.cpython.string import bytes_to_str +from sage.interfaces.expect import Expect, ExpectElement from sage.misc.instancedoc import instancedoc from sage.misc.temporary_file import tmp_filename -from sage.cpython.string import bytes_to_str +from sage.misc.verbose import verbose class Octave(Expect): @@ -186,6 +188,7 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, """ EXAMPLES:: + sage: from sage.interfaces.octave import octave sage: octave == loads(dumps(octave)) True """ diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 94ad62153a9..220eff4d56f 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -446,6 +446,7 @@ def clear(self, var): TESTS:: sage: # optional - jupymake + sage: from sage.interfaces.polymake import polymake sage: c = polymake.cube(15) sage: polymake._available_vars = [] sage: old = c._name diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index a2c0c09e37d..b3a16bb8531 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -264,19 +264,24 @@ # https://www.gnu.org/licenses/ # # ************************************************************************ -import os import logging +import os +import re -from .interface import Interface, InterfaceElement, InterfaceFunction, InterfaceFunctionElement from sage.env import DOT_SAGE -import re -from sage.structure.element import parent +from sage.features import PythonModule +from sage.interfaces.interface import ( + Interface, + InterfaceElement, + InterfaceFunction, + InterfaceFunctionElement, +) from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc # see the _lazy_init for some reasoning behind the lazy imports from sage.misc.lazy_import import lazy_import -from sage.features import PythonModule +from sage.structure.element import parent rpy2_feature = PythonModule('rpy2', spkg='rpy2', type='standard') @@ -371,7 +376,7 @@ def _setup_r_to_sage_converter(): sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs.sage() ['X1', 'Y2', 'X3', 'Y4', 'X5', 'Y6', 'X7', 'Y8', 'X9', 'Y10'] """ - from rpy2.rinterface import SexpVector, ListSexpVector, FloatSexpVector + from rpy2.rinterface import FloatSexpVector, ListSexpVector, SexpVector # convert rpy2's representation of r objects to the one sage expects (as defined by the old # expect interface) @@ -484,6 +489,7 @@ def __init__(self, TESTS:: + sage: from sage.interfaces.r import r sage: r == loads(dumps(r)) True """ diff --git a/src/sage/interfaces/sage0.py b/src/sage/interfaces/sage0.py index 591c1c73795..83ab256b2ce 100644 --- a/src/sage/interfaces/sage0.py +++ b/src/sage/interfaces/sage0.py @@ -535,7 +535,7 @@ def _repr_(self): EXAMPLES:: sage: sage0(4).gcd - + """ return str(self._obj.parent().eval('%s.%s' % (self._obj._name, self._name))) diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index c7faa284cfa..25e091164f4 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -337,24 +337,26 @@ import os import platform import re -import sys -import pexpect import shlex +import sys import time -from .expect import Expect, ExpectElement, FunctionElement, ExpectFunction - -import sage.interfaces.abc +import pexpect -from sage.interfaces.tab_completion import ExtraTabCompletion -from sage.structure.sequence import Sequence_generic -from sage.structure.element import RingElement import sage.features.singular - +import sage.interfaces.abc import sage.rings.integer - -from sage.misc.verbose import get_verbose +from sage.interfaces.expect import ( + Expect, + ExpectElement, + ExpectFunction, + FunctionElement, +) +from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc +from sage.misc.verbose import get_verbose +from sage.structure.element import RingElement +from sage.structure.sequence import Sequence_generic class SingularError(RuntimeError): @@ -390,6 +392,7 @@ def __init__(self, maxread=None, script_subdirectory=None, """ EXAMPLES:: + sage: from sage.interfaces.singular import singular sage: singular == loads(dumps(singular)) True """ @@ -1396,8 +1399,8 @@ def _repr_(self): s = self.parent().eval('pmat(%s,20)' % (self.name())) # compatibility for singular 4.3.2p10 and before if s.startswith("polynomial ring,"): - from sage.rings.polynomial.term_order import singular_name_mapping from sage.repl.rich_output import get_display_manager + from sage.rings.polynomial.term_order import singular_name_mapping # this is our cue that singular uses `rp` instead of `ip` if singular_name_mapping['invlex'] == 'rp' and 'doctest' in str(get_display_manager()): s = re.sub('^(// .*block.* : ordering )rp$', '\\1ip', @@ -1639,16 +1642,16 @@ def sage_global_ring(self): from sage.rings.rational_field import QQ br = QQ elif charstr[0].startswith('Float'): - from sage.rings.real_mpfr import RealField from sage.functions.other import ceil from sage.misc.functional import log + from sage.rings.real_mpfr import RealField prec = singular.eval('ringlist(basering)[1][2][1]') br = RealField(ceil((ZZ(prec) + 1) / log(2, 10))) is_extension = False elif charstr[0] == 'complex': - from sage.rings.complex_mpfr import ComplexField from sage.functions.other import ceil from sage.misc.functional import log + from sage.rings.complex_mpfr import ComplexField prec = singular.eval('ringlist(basering)[1][2][1]') br = ComplexField(ceil((ZZ(prec) + 1) / log(2, 10))) is_extension = False @@ -1684,8 +1687,8 @@ def sage_global_ring(self): # Now, we form the polynomial ring over BR with the given variables, # using Singular's term order - from sage.rings.polynomial.term_order import termorder_from_singular from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + from sage.rings.polynomial.term_order import termorder_from_singular # Meanwhile Singulars quotient rings are also of 'ring' type, not 'qring' as it was in the past. # To find out if a singular ring is a quotient ring or not checking for ring type does not help # and instead of that we check if the quotient ring is zero or not: @@ -1783,11 +1786,15 @@ def sage_poly(self, R=None, kcache=None): choose an appropriate conversion strategy """ # TODO: Refactor imports to move this to the top + from sage.rings.polynomial.multi_polynomial_libsingular import ( + MPolynomialRing_libsingular, + ) from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polydict import ETuple - from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + from sage.rings.polynomial.polynomial_singular_interface import ( + can_convert_to_singular, + ) from sage.rings.quotient_ring import QuotientRing_generic ring_is_fine = False diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index 9e5fa3c66dc..1c0a35bc888 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -1353,7 +1353,11 @@ cpdef EclObject ecl_eval(str s): """ cdef cl_object o - o = ecl_safe_eval(python_to_ecl(s, True)) - return ecl_wrap(o) + try: + o = ecl_safe_eval(python_to_ecl(s, True)) + return ecl_wrap(o) + except RuntimeError as e: + e.add_note(f"while evaluating {s}") + raise init_ecl() diff --git a/src/sage/libs/meson.build b/src/sage/libs/meson.build index 7cbbccf0091..6f8105ad7a7 100644 --- a/src/sage/libs/meson.build +++ b/src/sage/libs/meson.build @@ -5,15 +5,72 @@ if not ecl.found() and not is_windows ecl_proj = subproject('ecl') ecl = ecl_proj.get_variable('ecl_dep') endif -braiding = dependency('libbraiding', required: false) -if not braiding.found() - # Fallback since pkg-config support was only added in v1.3.1 - braiding = cc.find_library( - 'braiding', - required: not is_windows, - disabler: true, +ecl_bin = find_program('ecl', required: false) +if ecl_bin.found() + maxima_check = run_command( + ecl_bin, + '--eval', + '(require \'maxima)', + '--eval', + '(quit)', + check: false, ) + if maxima_check.returncode() == 0 + # ecl does not have any problems with Maxima, so nothing needs to be set here: + conf_data.set('SAGE_MAXIMA_FAS', '') + else + # Try Sage's custom maxima location + sage_maxima = join_paths( + get_option('SAGE_LOCAL'), + 'lib', + 'ecl', + 'maxima.fas', + ) + maxima_check = run_command( + ecl_bin, + '--eval', + '(require \'maxima "' + sage_maxima + '")', + '--eval', + '(quit)', + check: false, + ) + conf_data.set('SAGE_MAXIMA_FAS', sage_maxima) + endif + + maxima_bin = find_program('maxima', required: false, disabler: true) + maxima_present = maxima_check.returncode() == 0 and maxima_bin.found() +else + maxima_present = false +endif +if not maxima_present + if is_windows + # We currently cannot build Maxima on Windows, so we disable it + maxima = disabler() + else + # ECL does not have Maxima support + maxima_proj = subproject('maxima') + maxima = maxima_proj.get_variable('maxima_dep') + # Use the freshly built maxima + conf_data.set('SAGE_MAXIMA_FAS', maxima.get_variable(internal: 'MAXIMA_FAS')) + conf_data.set( + 'SAGE_MAXIMA_SHARE', + maxima.get_variable(internal: 'MAXIMA_SHARE'), + ) + conf_data.set('SAGE_MAXIMA', maxima.get_variable(internal: 'MAXIMA_BIN')) + endif +else + maxima = declare_dependency() + # ecl does not have any problems with Maxima, so nothing needs to be set here: + conf_data.set('SAGE_MAXIMA_SHARE', '') + conf_data.set('SAGE_MAXIMA', maxima_bin.full_path()) endif + +braiding = dependency( + 'libbraiding', + version: '>=1.3.1', + required: false, + disabler: true, +) gc = dependency( ['bdw-gc-threaded', 'bdw-gc'], version: '>=7.6.4', @@ -51,11 +108,13 @@ extension_data = { 'meataxe': files('meataxe.pyx'), } -dependencies = [py_dep, cysignals, ecl, gc, gmp] +dependencies = [py_dep, cysignals, gc, gmp] foreach name, pyx : extension_data deps = dependencies - if name == 'meataxe' + if name == 'ecl' + deps += [ecl, maxima] + elif name == 'meataxe' deps += [mtx] elif name == 'homfly' deps += [homfly] diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index 941ae911afe..841a7349d91 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -851,7 +851,7 @@ cpdef poison_currRing(frame, event, arg): sage: from sage.libs.singular.ring import poison_currRing sage: sys.settrace(poison_currRing) sage: sys.gettrace() - + sage: sys.settrace(previous_trace_func) # switch it off again """ global currRing diff --git a/src/sage/matrix/matrix0.pxd b/src/sage/matrix/matrix0.pxd index 00e0bb5b196..f8dd8158125 100644 --- a/src/sage/matrix/matrix0.pxd +++ b/src/sage/matrix/matrix0.pxd @@ -48,6 +48,7 @@ cdef class Matrix(sage.structure.element.Matrix): # Unsafe entry access cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, object x) cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc) cdef _coerce_element(self, x) cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1 diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 22a7a02d9e0..9aee0007f1f 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -556,6 +556,28 @@ cdef class Matrix(sage.structure.element.Matrix): """ raise NotImplementedError("this must be defined in the derived type.") + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copy element (iSrc, jSrc) from ``src`` to position (iDst, jDst) in + ``self``. It is assumed ``src`` is the same type of matrix as``self``, + with the same base ring. + + This should generally be reimplemented in subclasses to avoid the type + conversion that often is necessary in ``get_unsafe`` and + ``set_unsafe``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be the same type as + ``self`` with the same base ring. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + """ + cdef Matrix _src = src + self.set_unsafe(iDst, jDst, _src.get_unsafe(iSrc, jSrc)) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: """ Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 85c9833a3d6..df1cfe5f298 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -2043,7 +2043,7 @@ cdef class Matrix(Matrix0): if col < 0 or col >= self._ncols: raise IndexError("column index out of range") for i in range(self._nrows): - A.set_unsafe(i, j, self.get_unsafe(i, col)) + A.copy_from_unsafe(i, j, self, i, col) return A def delete_columns(self, dcols, check=True): @@ -2141,7 +2141,7 @@ cdef class Matrix(Matrix0): if row < 0 or row >= self._nrows: raise IndexError("row index out of range") for j in range(self._ncols): - A.set_unsafe(i, j, self.get_unsafe(row, j)) + A.copy_from_unsafe(i, j, self, row, j) return A def delete_rows(self, drows, check=True): @@ -2268,7 +2268,7 @@ cdef class Matrix(Matrix0): if row < 0 or row >= self._nrows: raise IndexError("row index out of range") for j, col in enumerate(columns): - A.set_unsafe(i, j, self.get_unsafe(row, col)) + A.copy_from_unsafe(i, j, self, row, col) return A def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0, diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d2cc1423128..e5f2ebb453f 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -901,7 +901,6 @@ cdef class Matrix(Matrix1): sage: v = matrix.identity(QQ, 500).solve_right(vector(QQ, [1]*500), extend=False) # <1s sage: matrix.identity(QQ, 500).hermite_form() # not tested (slow) sage: v = (matrix.identity(ZZ, 500)*2).solve_right(vector(ZZ, [2]*500), extend=False) # <1s - sage: matrix.identity(ZZ, 500).hermite_form() # not tested (slow) sage: m = matrix.identity(ZZ, 250).stack(matrix.identity(ZZ, 250))*2 sage: v = m.solve_right(vector(ZZ, [2]*500), extend=False) # <1s sage: m._solve_right_hermite_form(matrix(ZZ, [[2]]*500)) # not tested (slow) @@ -974,10 +973,11 @@ cdef class Matrix(Matrix1): if P not in _Fields and not extend: if self.rank() == self.ncols(): # hermite_form is slow, avoid if possible + F = P.fraction_field() if self.is_square(): - X = self._solve_right_nonsingular_square(C, check_rank=False) + X = self.change_ring(F)._solve_right_nonsingular_square(C.change_ring(F), check_rank=False) else: - X = self._solve_right_general(C) + X = self.change_ring(F)._solve_right_general(C.change_ring(F)) try: X = X.change_ring(P) except TypeError: @@ -16484,6 +16484,11 @@ cdef class Matrix(Matrix1): sage: matrix(CDF, 2, 2, sparse=True).norm(1) 0.0 + + Check the euclidean norm for a sparse matrix (:issue:`40492`):: + + sage: matrix(ZZ, [[1, 2], [3, 4]], sparse=True).norm() + 5.464985704219043 """ from sage.rings.real_double import RDF @@ -16494,8 +16499,11 @@ cdef class Matrix(Matrix1): if p == 2: from sage.rings.complex_double import CDF - A = self.change_ring(CDF) - A = A.conjugate().transpose() * A + # Always try to convert to ``dense_matrix`` since sparse matrices + # don't expose the ``SVD`` method. If the matrix is already dense, + # the cost is negligible. + A = self.dense_matrix().change_ring(CDF) + A = A.conjugate_transpose() * A S = A.SVD()[1] return max(S.list()).real().sqrt() diff --git a/src/sage/matrix/matrix_complex_ball_dense.pyx b/src/sage/matrix/matrix_complex_ball_dense.pyx index b8b193145c7..952212c40fc 100644 --- a/src/sage/matrix/matrix_complex_ball_dense.pyx +++ b/src/sage/matrix/matrix_complex_ball_dense.pyx @@ -307,6 +307,53 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): acb_set(z.value, acb_mat_entry(self.value, i, j)) return z + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + .. warning:: + + This is very unsafe; it assumes ``iSrc``, ``jSrc``, ``iDst`` and + ``jDst`` are in the right range, and that ``src`` is a + Matrix_complex_ball_dense with the same base ring as ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a + Matrix_complex_ball_dense with the same base ring as + ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = MatrixSpace(CBF,3,4)(range(12)) + sage: m + [ 0 1.000000000000000 2.000000000000000 3.000000000000000] + [4.000000000000000 5.000000000000000 6.000000000000000 7.000000000000000] + [8.000000000000000 9.000000000000000 10.00000000000000 11.00000000000000] + sage: m.transpose() + [ 0 4.000000000000000 8.000000000000000] + [1.000000000000000 5.000000000000000 9.000000000000000] + [2.000000000000000 6.000000000000000 10.00000000000000] + [3.000000000000000 7.000000000000000 11.00000000000000] + sage: m.matrix_from_rows([0,2]) + [ 0 1.000000000000000 2.000000000000000 3.000000000000000] + [8.000000000000000 9.000000000000000 10.00000000000000 11.00000000000000] + sage: m.matrix_from_columns([1,3]) + [1.000000000000000 3.000000000000000] + [5.000000000000000 7.000000000000000] + [9.000000000000000 11.00000000000000] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [4.000000000000000 7.000000000000000] + [8.000000000000000 11.00000000000000] + """ + cdef Matrix_complex_ball_dense _src = src + acb_set(acb_mat_entry(self.value, iDst, jDst), acb_mat_entry(_src.value, iSrc, jSrc)) + cpdef _richcmp_(left, right, int op): r""" EXAMPLES:: @@ -558,11 +605,42 @@ cdef class Matrix_complex_ball_dense(Matrix_dense): [3.000000000000000 6.000000000000000] sage: m.transpose().parent() Full MatrixSpace of 3 by 2 dense matrices over Complex ball field with 53 bits of precision + + TESTS:: + + sage: m = matrix(CBF,2,3,range(6)) + sage: m.subdivide([1],[2]) + sage: m + [ 0 1.000000000000000|2.000000000000000] + [-----------------------------------+-----------------] + [3.000000000000000 4.000000000000000|5.000000000000000] + sage: m.transpose() + [ 0|3.000000000000000] + [1.000000000000000|4.000000000000000] + [-----------------+-----------------] + [2.000000000000000|5.000000000000000] + + sage: m = matrix(CBF,0,2) + sage: m.subdivide([],[1]) + sage: m.subdivisions() + ([], [1]) + sage: m.transpose().subdivisions() + ([1], []) + + sage: m = matrix(CBF,2,0) + sage: m.subdivide([1],[]) + sage: m.subdivisions() + ([1], []) + sage: m.transpose().subdivisions() + ([], [1]) """ cdef Py_ssize_t nc = self._ncols cdef Py_ssize_t nr = self._nrows cdef Matrix_complex_ball_dense trans = self._new(nc, nr) acb_mat_transpose(trans.value, self.value) + if self._subdivisions is not None: + row_divs, col_divs = self.subdivisions() + trans.subdivide(col_divs, row_divs) return trans def _solve_right_nonsingular_square(self, Matrix_complex_ball_dense rhs, check_rank=None): diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index 5519882cd12..b393055c3ef 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -407,6 +407,53 @@ cdef class Matrix_cyclo_dense(Matrix_dense): return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copy the (iSrc,jSrc)-th entry of ``src`` to the (iDst,jDst)-th entry + ``self``. + + WARNING: As the name suggests, expect segfaults if iSrc,jSrc,iDst,jDst + are out of bounds!! This is for internal use only. This method assumes + ``src`` is a Matrix_cyclo_dense with the same base ring as ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_cyclo_dense + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: K. = CyclotomicField(3) + sage: M = matrix(K,3,4,[i + z/(i+1) for i in range(12)]) + sage: M + [ z 1/2*z + 1 1/3*z + 2 1/4*z + 3] + [ 1/5*z + 4 1/6*z + 5 1/7*z + 6 1/8*z + 7] + [ 1/9*z + 8 1/10*z + 9 1/11*z + 10 1/12*z + 11] + sage: M.transpose() + [ z 1/5*z + 4 1/9*z + 8] + [ 1/2*z + 1 1/6*z + 5 1/10*z + 9] + [ 1/3*z + 2 1/7*z + 6 1/11*z + 10] + [ 1/4*z + 3 1/8*z + 7 1/12*z + 11] + sage: M.matrix_from_rows([0,2]) + [ z 1/2*z + 1 1/3*z + 2 1/4*z + 3] + [ 1/9*z + 8 1/10*z + 9 1/11*z + 10 1/12*z + 11] + sage: M.matrix_from_columns([1,3]) + [ 1/2*z + 1 1/4*z + 3] + [ 1/6*z + 5 1/8*z + 7] + [ 1/10*z + 9 1/12*z + 11] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 1/5*z + 4 1/8*z + 7] + [ 1/9*z + 8 1/12*z + 11] + """ + cdef Matrix_cyclo_dense _src = src + cdef int a + for a in range(self._degree): + self._matrix.copy_from_unsafe(a, jDst + iDst*self._ncols, _src._matrix, a, jSrc + iSrc*_src._ncols) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: r""" Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 471fe521bf0..d52b5e2d3e7 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -138,7 +138,7 @@ cdef class Matrix_dense(matrix.Matrix): cdef Py_ssize_t i, j for j from 0<= j < nc: for i from 0<= i < nr: - trans.set_unsafe(j,i,self.get_unsafe(i,j)) + trans.copy_from_unsafe(j, i, self, i, j) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() @@ -183,7 +183,7 @@ cdef class Matrix_dense(matrix.Matrix): rj -= 1 for i from 0 <= i < nr: ri -= 1 - atrans.set_unsafe(j, i, self.get_unsafe(ri, rj)) + atrans.copy_from_unsafe(j, i, self, ri, rj) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() diff --git a/src/sage/matrix/matrix_gap.pyx b/src/sage/matrix/matrix_gap.pyx index f5a6e1d10e7..13f323bf0d6 100644 --- a/src/sage/matrix/matrix_gap.pyx +++ b/src/sage/matrix/matrix_gap.pyx @@ -204,6 +204,46 @@ cdef class Matrix_gap(Matrix_dense): """ self._libgap[i,j] = x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_gap with the + same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: M = MatrixSpace(ZZ, 3, 4, implementation='gap')(range(12)) + sage: M + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + sage: M.transpose() + [ 0 4 8] + [ 1 5 9] + [ 2 6 10] + [ 3 7 11] + sage: M.matrix_from_rows([0,2]) + [ 0 1 2 3] + [ 8 9 10 11] + sage: M.matrix_from_columns([1,3]) + [ 1 3] + [ 5 7] + [ 9 11] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4 7] + [ 8 11] + """ + cdef Matrix_gap _src = src + self._libgap[iDst,jDst] = _src._libgap[iSrc,jSrc] + cpdef _richcmp_(self, other, int op): r""" Compare ``self`` and ``right``. @@ -342,10 +382,44 @@ cdef class Matrix_gap(Matrix_dense): [ 4] [ 2] [52] + + TESTS:: + + sage: M = MatrixSpace(QQ, 2, 3, implementation='gap') + sage: m = M(range(6)) + sage: m.subdivide([1],[2]) + sage: m + [0 1|2] + [---+-] + [3 4|5] + sage: m.transpose() + [0|3] + [1|4] + [-+-] + [2|5] + + sage: M = MatrixSpace(QQ, 0, 2, implementation='gap') + sage: m = M([]) + sage: m.subdivide([],[1]) + sage: m.subdivisions() + ([], [1]) + sage: m.transpose().subdivisions() + ([1], []) + + sage: M = MatrixSpace(QQ, 2, 0, implementation='gap') + sage: m = M([]) + sage: m.subdivide([1],[]) + sage: m.subdivisions() + ([1], []) + sage: m.transpose().subdivisions() + ([], [1]) """ cdef Matrix_gap M M = self._new(self._ncols, self._nrows) M._libgap = self._libgap.TransposedMat() + if self._subdivisions is not None: + row_divs, col_divs = self.subdivisions() + M.subdivide(col_divs, row_divs) return M def determinant(self): diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index 28603b5a930..7356dc1bcc7 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -99,6 +99,47 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): return self._entries[i*self._ncols + j] + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_generic_dense + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: K. = GF(9) + sage: m = matrix(K,3,4,[((i%9)//3)*z + i%3 for i in range(12)]) + sage: m + [ 0 1 2 z] + [ z + 1 z + 2 2*z 2*z + 1] + [2*z + 2 0 1 2] + sage: m.transpose() + [ 0 z + 1 2*z + 2] + [ 1 z + 2 0] + [ 2 2*z 1] + [ z 2*z + 1 2] + sage: m.matrix_from_rows([0,2]) + [ 0 1 2 z] + [2*z + 2 0 1 2] + sage: m.matrix_from_columns([1,3]) + [ 1 z] + [ z + 2 2*z + 1] + [ 0 2] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ z + 1 2*z + 1] + [2*z + 2 2] + """ + cdef Matrix_generic_dense _src = src + self._entries[iDst*self._ncols + jDst] = _src._entries[iSrc*_src._ncols + jSrc] + def _reverse_unsafe(self): r""" TESTS:: diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index 0fba0426cf2..74cfc64b2c8 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -200,6 +200,50 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): return self._entries.get((i,j), self._zero) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_generic_sparse + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: K. = GF(9) + sage: m = matrix(K,3,4,[((i%9)//3)*z + i%3 if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: m + [ 0 0 2 z] + [ 0 z + 2 0 2*z + 1] + [ 0 0 0 2] + sage: m.transpose() + [ 0 0 0] + [ 0 z + 2 0] + [ 2 0 0] + [ z 2*z + 1 2] + sage: m.matrix_from_rows([0,2]) + [0 0 2 z] + [0 0 0 2] + sage: m.matrix_from_columns([1,3]) + [ 0 z] + [ z + 2 2*z + 1] + [ 0 2] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 2*z + 1] + [ 0 2] + """ + cdef Matrix_generic_sparse _src = src + if (iSrc,jSrc) in _src._entries: + self._entries[(iDst,jDst)] = _src._entries.get((iSrc, jSrc), _src._zero) + elif (iDst,jDst) in self._entries: + del self._entries[(iDst,jDst)] + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: """ Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index e90ce0b71cb..4a36cbb7ece 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -284,6 +284,47 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): cdef Cache_base cache = self._base_ring._cache return cache.fetch_int(r) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_gf2e_dense with + the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: K. = GF(512) + sage: m = matrix(K,3,4,[sum([(i//(2^j))%2 * z^j for j in range(4)]) for i in range(12)]) + sage: m + [ 0 1 z z + 1] + [ z^2 z^2 + 1 z^2 + z z^2 + z + 1] + [ z^3 z^3 + 1 z^3 + z z^3 + z + 1] + sage: m.transpose() + [ 0 z^2 z^3] + [ 1 z^2 + 1 z^3 + 1] + [ z z^2 + z z^3 + z] + [ z + 1 z^2 + z + 1 z^3 + z + 1] + sage: m.matrix_from_rows([0,2]) + [ 0 1 z z + 1] + [ z^3 z^3 + 1 z^3 + z z^3 + z + 1] + sage: m.matrix_from_columns([1,3]) + [ 1 z + 1] + [ z^2 + 1 z^2 + z + 1] + [ z^3 + 1 z^3 + z + 1] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ z^2 z^2 + z + 1] + [ z^3 z^3 + z + 1] + """ + cdef Matrix_gf2e_dense _src = src + mzed_write_elem(self._entries, iDst, jDst, mzed_read_elem(_src._entries, iSrc, jSrc)) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: r""" Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index ea56e04afbe..42aa71a6bda 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -673,6 +673,47 @@ cdef class Matrix_gfpn_dense(Matrix_dense): finally: sig_off() + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_gfpn_dense with + the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: K. = GF(59) + sage: M = MatrixSpace(K, 3, 4, implementation=Matrix_gfpn_dense)(range(12)) + sage: M + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + sage: M.transpose() + [ 0 4 8] + [ 1 5 9] + [ 2 6 10] + [ 3 7 11] + sage: M.matrix_from_rows([0,2]) + [ 0 1 2 3] + [ 8 9 10 11] + sage: M.matrix_from_columns([1,3]) + [ 1 3] + [ 5 7] + [ 9 11] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4 7] + [ 8 11] + """ + cdef Matrix_gfpn_dense _src = src + FfInsert(FfGetPtr(self.Data.Data, iDst), jDst, FfExtract(MatGetPtr(_src.Data,iSrc), jSrc)) + def randomize(self, density=None, nonzero=False, *args, **kwds): """ Fill the matrix with random values. diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index aacd02d1aeb..f15380ad1db 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -476,6 +476,48 @@ cdef class Matrix_integer_dense(Matrix_dense): """ return fmpz_is_zero(fmpz_mat_entry(self._matrix, i,j)) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copy position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. + + The object ``src`` must be of type ``Matrix_integer_dense`` and have + the same base ring as ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_integer_dense + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = matrix(ZZ,3,4,range(12)) + sage: m + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + sage: m.transpose() + [ 0 4 8] + [ 1 5 9] + [ 2 6 10] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 1 2 3] + [ 8 9 10 11] + sage: m.matrix_from_columns([1,3]) + [ 1 3] + [ 5 7] + [ 9 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4 7] + [ 8 11] + """ + cdef Matrix_integer_dense _src = src + fmpz_set(fmpz_mat_entry(self._matrix, iDst, jDst), fmpz_mat_entry(_src._matrix, iSrc, jSrc)) + def _pickle(self): """ EXAMPLES:: diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index a5f982a19e6..45f92acf0b6 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -118,6 +118,51 @@ cdef class Matrix_integer_sparse(Matrix_sparse): mpz_vector_get_entry(x.value, &self._matrix[i], j) return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + """ + Copy position iSrc,jSrc of ``src`` to position iDst,jDst of ``self``. + + The object ``src`` must be of type ``Matrix_integer_sparse`` and have + the same base ring as ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_integer_sparse + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = matrix(ZZ,3,4,[i if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: m + [ 0 0 2 3] + [ 0 5 0 7] + [ 0 0 0 11] + sage: m.transpose() + [ 0 0 0] + [ 0 5 0] + [ 2 0 0] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 0 2 3] + [ 0 0 0 11] + sage: m.matrix_from_columns([1,3]) + [ 0 3] + [ 5 7] + [ 0 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 7] + [ 0 11] + """ + cdef Integer x + x = Integer() + cdef Matrix_integer_sparse _src = src + mpz_vector_get_entry(x.value, &_src._matrix[iSrc], jSrc) + mpz_vector_set_entry(&self._matrix[iDst], jDst, x.value) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: """ Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index f3fb83827ba..7aff8c67fe3 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -360,6 +360,46 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse else: return self._zero + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_mod2_dense with + the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = matrix(GF(2),3,4,[is_prime(i) for i in range(12)]) + sage: m + [0 0 1 1] + [0 1 0 1] + [0 0 0 1] + sage: m.transpose() + [0 0 0] + [0 1 0] + [1 0 0] + [1 1 1] + sage: m.matrix_from_rows([0,2]) + [0 0 1 1] + [0 0 0 1] + sage: m.matrix_from_columns([1,3]) + [0 1] + [1 1] + [0 1] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [0 1] + [0 1] + """ + cdef Matrix_mod2_dense _src = src + mzd_write_bit(self._entries, iDst, jDst, mzd_read_bit(_src._entries, iSrc, jSrc)) + def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None, *, unicode=False, shape=None, character_art=False, left_border=None, right_border=None, @@ -1493,15 +1533,29 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse sage: A[0,0] = 0 sage: B[0,0] 1 + + sage: m = matrix(GF(2),0,2) + sage: m.subdivide([],[1]) + sage: m.subdivisions() + ([], [1]) + sage: m.transpose().subdivisions() + ([1], []) + + sage: m = matrix(GF(2),2,0) + sage: m.subdivide([1],[]) + sage: m.subdivisions() + ([1], []) + sage: m.transpose().subdivisions() + ([], [1]) """ cdef Matrix_mod2_dense A = self.new_matrix(ncols=self._nrows, nrows=self._ncols) - if self._nrows == 0 or self._ncols == 0: - return A + if self._nrows != 0 and self._ncols != 0: + A._entries = mzd_transpose(A._entries, self._entries) - A._entries = mzd_transpose(A._entries, self._entries) if self._subdivisions is not None: - A.subdivide(*self.subdivisions()) + row_divs, col_divs = self.subdivisions() + A.subdivide(col_divs, row_divs) return A cpdef _richcmp_(self, right, int op): diff --git a/src/sage/matrix/matrix_modn_dense_double.pyx b/src/sage/matrix/matrix_modn_dense_double.pyx index ecb41e7d5dd..1e8e8c193a2 100644 --- a/src/sage/matrix/matrix_modn_dense_double.pyx +++ b/src/sage/matrix/matrix_modn_dense_double.pyx @@ -175,3 +175,45 @@ cdef class Matrix_modn_dense_double(Matrix_modn_dense_template): return (_self._get_template)._new_c(result) else: return (_self._get_template)._new_c(result) + + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a + Matrix_modn_dense_double with the same base ring as + ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = matrix(GF(257),3,4,range(12)) + sage: m + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + sage: m.transpose() + [ 0 4 8] + [ 1 5 9] + [ 2 6 10] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 1 2 3] + [ 8 9 10 11] + sage: m.matrix_from_columns([1,3]) + [ 1 3] + [ 5 7] + [ 9 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4 7] + [ 8 11] + """ + cdef Matrix_modn_dense_double _src = src + self._matrix[iDst][jDst] = _src._matrix[iSrc][jSrc] + \ No newline at end of file diff --git a/src/sage/matrix/matrix_modn_dense_float.pyx b/src/sage/matrix/matrix_modn_dense_float.pyx index 13dedf8441c..e04250ee99a 100644 --- a/src/sage/matrix/matrix_modn_dense_float.pyx +++ b/src/sage/matrix/matrix_modn_dense_float.pyx @@ -151,3 +151,43 @@ cdef class Matrix_modn_dense_float(Matrix_modn_dense_template): """ cdef float result = (self)._matrix[i][j] return (self)._get_template._new_c(result) + + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_modn_dense_float + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = matrix(GF(131),3,4,range(12)) + sage: m + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + sage: m.transpose() + [ 0 4 8] + [ 1 5 9] + [ 2 6 10] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 1 2 3] + [ 8 9 10 11] + sage: m.matrix_from_columns([1,3]) + [ 1 3] + [ 5 7] + [ 9 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4 7] + [ 8 11] + """ + cdef Matrix_modn_dense_float _src = src + self._matrix[iDst][jDst] = _src._matrix[iSrc][jSrc] diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index 9b7cdcd2dcb..8155f95f9ca 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -182,6 +182,46 @@ cdef class Matrix_modn_sparse(Matrix_sparse): n.ivalue = get_entry(&self.rows[i], j) return n + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_modn_sparse + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: m = matrix(GF(257),3,4,[i if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: m + [ 0 0 2 3] + [ 0 5 0 7] + [ 0 0 0 11] + sage: m.transpose() + [ 0 0 0] + [ 0 5 0] + [ 2 0 0] + [ 3 7 11] + sage: m.matrix_from_rows([0,2]) + [ 0 0 2 3] + [ 0 0 0 11] + sage: m.matrix_from_columns([1,3]) + [ 0 3] + [ 5 7] + [ 0 11] + sage: m.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 7] + [ 0 11] + """ + cdef Matrix_modn_sparse _src = src + set_entry(&self.rows[iDst], jDst, get_entry(&_src.rows[iSrc], jSrc)) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: """ Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_numpy_dense.pyx b/src/sage/matrix/matrix_numpy_dense.pyx index e6420bf29c8..dbc0b6130d5 100644 --- a/src/sage/matrix/matrix_numpy_dense.pyx +++ b/src/sage/matrix/matrix_numpy_dense.pyx @@ -177,6 +177,46 @@ cdef class Matrix_numpy_dense(Matrix_dense): return self._sage_dtype(cnumpy.PyArray_GETITEM(self._matrix_numpy, cnumpy.PyArray_GETPTR2(self._matrix_numpy, i, j))) + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_numpy_dense + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: M = MatrixSpace(RDF, 3, 4)(range(12)) + sage: M + [ 0.0 1.0 2.0 3.0] + [ 4.0 5.0 6.0 7.0] + [ 8.0 9.0 10.0 11.0] + sage: M.transpose() + [ 0.0 4.0 8.0] + [ 1.0 5.0 9.0] + [ 2.0 6.0 10.0] + [ 3.0 7.0 11.0] + sage: M.matrix_from_rows([0,2]) + [ 0.0 1.0 2.0 3.0] + [ 8.0 9.0 10.0 11.0] + sage: M.matrix_from_columns([1,3]) + [ 1.0 3.0] + [ 5.0 7.0] + [ 9.0 11.0] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 4.0 7.0] + [ 8.0 11.0] + """ + cdef Matrix_numpy_dense _src = src + cnumpy.PyArray_SETITEM(self._matrix_numpy, cnumpy.PyArray_GETPTR2(self._matrix_numpy, iDst, jDst), cnumpy.PyArray_GETITEM(_src._matrix_numpy, cnumpy.PyArray_GETPTR2(_src._matrix_numpy, iSrc, jSrc))) + cdef Matrix_numpy_dense _new(self, int nrows=-1, int ncols=-1): """ Return a new uninitialized matrix with same parent as ``self``. @@ -266,13 +306,40 @@ cdef class Matrix_numpy_dense(Matrix_dense): [] sage: m.transpose().parent() Full MatrixSpace of 3 by 0 dense matrices over Real Double Field + + TESTS:: + + sage: m = matrix(RDF,2,3,range(6)) + sage: m.subdivide([1],[2]) + sage: m + [0.0 1.0|2.0] + [-------+---] + [3.0 4.0|5.0] + sage: m.transpose() + [0.0|3.0] + [1.0|4.0] + [---+---] + [2.0|5.0] + + sage: m = matrix(RDF,0,2) + sage: m.subdivide([],[1]) + sage: m.subdivisions() + ([], [1]) + sage: m.transpose().subdivisions() + ([1], []) + + sage: m = matrix(RDF,2,0) + sage: m.subdivide([1],[]) + sage: m.subdivisions() + ([1], []) + sage: m.transpose().subdivisions() + ([], [1]) """ - if self._nrows == 0 or self._ncols == 0: - return self.new_matrix(self._ncols, self._nrows) + cdef Matrix_numpy_dense trans = self._new(self._ncols, self._nrows) + + if self._nrows != 0 and self._ncols != 0: + trans._matrix_numpy = self._matrix_numpy.transpose().copy() - cdef Matrix_numpy_dense trans - trans = self._new(self._ncols, self._nrows) - trans._matrix_numpy = self._matrix_numpy.transpose().copy() if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() trans.subdivide(col_divs, row_divs) diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index aa941292787..786809efaf4 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -264,6 +264,46 @@ cdef class Matrix_rational_dense(Matrix_dense): fmpq_get_mpq(x.value, fmpq_mat_entry(self._matrix, i, j)) return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_rational_dense + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: M = matrix(QQ,3,4,[i + 1/(i+1) for i in range(12)]) + sage: M + [ 1 3/2 7/3 13/4] + [ 21/5 31/6 43/7 57/8] + [ 73/9 91/10 111/11 133/12] + sage: M.transpose() + [ 1 21/5 73/9] + [ 3/2 31/6 91/10] + [ 7/3 43/7 111/11] + [ 13/4 57/8 133/12] + sage: M.matrix_from_rows([0,2]) + [ 1 3/2 7/3 13/4] + [ 73/9 91/10 111/11 133/12] + sage: M.matrix_from_columns([1,3]) + [ 3/2 13/4] + [ 31/6 57/8] + [ 91/10 133/12] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 21/5 57/8] + [ 73/9 133/12] + """ + cdef Matrix_rational_dense _src = src + fmpq_set(fmpq_mat_entry(self._matrix, iDst, jDst), fmpq_mat_entry(_src._matrix, iSrc, jSrc)) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: """ Return 1 if the entry (i, j) is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index 8d86b09258a..0ea992e12dc 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -102,6 +102,49 @@ cdef class Matrix_rational_sparse(Matrix_sparse): mpq_vector_get_entry(x.value, &self._matrix[i], j) return x + cdef copy_from_unsafe(self, Py_ssize_t iDst, Py_ssize_t jDst, src, Py_ssize_t iSrc, Py_ssize_t jSrc): + r""" + Copy the ``(iSrc, jSrc)`` entry of ``src`` into the ``(iDst, jDst)`` + entry of ``self``. + + INPUT: + + - ``iDst`` - the row to be copied to in ``self``. + - ``jDst`` - the column to be copied to in ``self``. + - ``src`` - the matrix to copy from. Should be a Matrix_rational_sparse + with the same base ring as ``self``. + - ``iSrc`` - the row to be copied from in ``src``. + - ``jSrc`` - the column to be copied from in ``src``. + + TESTS:: + + sage: M = matrix(QQ,3,4,[i + 1/(i+1) if is_prime(i) else 0 for i in range(12)],sparse=True) + sage: M + [ 0 0 7/3 13/4] + [ 0 31/6 0 57/8] + [ 0 0 0 133/12] + sage: M.transpose() + [ 0 0 0] + [ 0 31/6 0] + [ 7/3 0 0] + [ 13/4 57/8 133/12] + sage: M.matrix_from_rows([0,2]) + [ 0 0 7/3 13/4] + [ 0 0 0 133/12] + sage: M.matrix_from_columns([1,3]) + [ 0 13/4] + [ 31/6 57/8] + [ 0 133/12] + sage: M.matrix_from_rows_and_columns([1,2],[0,3]) + [ 0 57/8] + [ 0 133/12] + """ + cdef Rational x + x = Rational() + cdef Matrix_rational_sparse _src = src + mpq_vector_get_entry(x.value, &_src._matrix[iSrc], jSrc) + mpq_vector_set_entry(&self._matrix[iDst], jDst, x.value) + cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1: """ Return 1 if the entry ``(i, j)`` is zero, otherwise 0. diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 2ed725679f7..be8d3dff702 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -432,7 +432,7 @@ cdef class Matrix_sparse(matrix.Matrix): for k from 0 <= k < len(nz): i = get_ij(nz, k, 0) j = get_ij(nz, k, 1) - A.set_unsafe(j,i,self.get_unsafe(i,j)) + A.copy_from_unsafe(j, i, self, i, j) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() A.subdivide(col_divs, row_divs) @@ -464,7 +464,7 @@ cdef class Matrix_sparse(matrix.Matrix): for k from 0 <= k < len(nz): i = get_ij(nz, k, 0) j = get_ij(nz, k, 1) - A.set_unsafe(self._ncols-j-1, self._nrows-i-1,self.get_unsafe(i,j)) + A.copy_from_unsafe(self._ncols-j-1, self._nrows-i-1, self, i, j) if self._subdivisions is not None: row_divs, col_divs = self.subdivisions() A.subdivide(list(reversed([self._ncols - t for t in col_divs])), diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index bc7c8653e0e..b8813cf68f8 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -2695,8 +2695,6 @@ cdef class Matroid(SageObject): if not self._is_independent(X): yield X - dependent_r_sets = deprecated_function_alias(38057, dependent_sets) - cpdef SetSystem dependent_sets(self, long k): r""" Return the dependent sets of fixed size. diff --git a/src/sage/meson.build b/src/sage/meson.build index 0b7633e0b64..d1d15cf6895 100644 --- a/src/sage/meson.build +++ b/src/sage/meson.build @@ -16,9 +16,6 @@ if not fs.exists(datadir / 'cremona') 'Warning: The specified datadir does not contain the necessary Cremona database. Either specify a different datadir or specify a correct the correct path via the environment variable SAGE_SHARE during runtime.', ) endif -conf_data.set('SAGE_MAXIMA', maxima.full_path()) -# Conda's ecl does not have any problems with Maxima, so nothing needs to be set here: -conf_data.set('SAGE_MAXIMA_FAS', '') # Kenzo cannot yet be provided by the system, so we always use the SAGE_LOCAL path for now. conf_data.set('SAGE_KENZO_FAS', '\'${prefix}\'/lib/ecl/kenzo.fas') # It can be found, so we don't have to set anything here: @@ -59,14 +56,6 @@ ecm_bin = find_program( ) conf_data.set('SAGE_ECMBIN', ecm_bin.full_path()) -config_file = configure_file( - input: '../../pkgs/sage-conf/_sage_conf/_conf.py.in', - output: 'config.py', - install_dir: sage_install_dir, - install: true, - configuration: conf_data, -) - # Packages that need no processing and can be installed directly no_processing = [ 'cli', @@ -163,3 +152,13 @@ configure_file( install: true, configuration: kernel_data, ) + +# Write config file +# Should be last so that subdir calls can modify the config data +config_file = configure_file( + input: '../../pkgs/sage-conf/_sage_conf/_conf.py.in', + output: 'config.py', + install_dir: sage_install_dir, + install: true, + configuration: conf_data, +) diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index 11d614b3cc8..0b2ee1ff40d 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -1113,7 +1113,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: x._bases [5, 2] sage: x._key - + sage: x._key(10) 10 diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index 5e8930a3a24..223815222a5 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -71,7 +71,7 @@ cdef class _lazy_attribute(): sage: Parent.element_class.__name__ 'element_class' sage: Parent.element_class.__module__ - 'sage.misc.lazy_attribute' + 'sage.structure.parent' """ raise NotImplementedError("Only instantiate wrapper python class") diff --git a/src/sage/misc/lazy_import.pxd b/src/sage/misc/lazy_import.pxd new file mode 100644 index 00000000000..1fd4dcc448d --- /dev/null +++ b/src/sage/misc/lazy_import.pxd @@ -0,0 +1,12 @@ +cdef class LazyImport: + cdef readonly object _object # The actual object if imported, None otherwise + cdef object _module + cdef object _name + cdef object _as_name + cdef object _namespace + cdef bint _at_startup + cdef object _deprecation + cdef object _feature + + cdef inline get_object(self) + cpdef _get_object(self) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index f309429537b..58365b2b272 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -183,15 +183,6 @@ cdef class LazyImport(): ... TypeError: no conversion of this rational to integer """ - cdef readonly _object # The actual object if imported, None otherwise - cdef _module - cdef _name - cdef _as_name - cdef _namespace - cdef bint _at_startup - cdef _deprecation - cdef _feature - def __init__(self, module, name, as_name=None, at_startup=False, namespace=None, deprecation=None, feature=None): """ diff --git a/src/sage/misc/meson.build b/src/sage/misc/meson.build index 50e8000c46d..5a6e139e39d 100644 --- a/src/sage/misc/meson.build +++ b/src/sage/misc/meson.build @@ -38,6 +38,7 @@ py.install_sources( 'latex_macros.py', 'latex_standalone.py', 'lazy_format.py', + 'lazy_import.pxd', 'lazy_import_cache.py', 'lazy_list.pxd', 'lazy_string.pxd', diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index dd08f6ffbbc..a5711ef8d5f 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -45,6 +45,7 @@ comp_other = bz2 from sage.misc.sage_unittest import TestSuite from sage.misc.superseded import deprecation +from sage.misc.lazy_import cimport LazyImport # We define two global dictionaries `already_pickled` and # `already_unpickled`, which are intended to help you to implement @@ -331,7 +332,10 @@ def dumps(obj, compress=True): if make_pickle_jar: picklejar(obj) try: - ans = obj.dumps(compress) + type_obj = type(obj) + if type_obj is LazyImport: + type_obj = type((obj).get_object()) + ans = type_obj.dumps(obj, compress) except (AttributeError, RuntimeError, TypeError): ans = _base_dumps(obj, compress=compress) already_pickled = {} diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 028e0cf16cb..21a6daf6d19 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -149,7 +149,7 @@ def is_function_or_cython_function(obj): sage: is_function_or_cython_function(_mul_parent) True sage: is_function_or_cython_function(Integer.digits) # unbound method - False + True sage: is_function_or_cython_function(Integer(1).digits) # bound method False diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 30276672710..38a734bad1f 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -1559,14 +1559,10 @@ def _fplll_enumerate(self, target=None): """ L = self.LLL() dim = L.dimension() - gram = L.gram_matrix() basis = L.basis_matrix() import fpylll - gmat = fpylll.IntegerMatrix(dim, dim) - for i in range(dim): - for j in range(dim): - gmat[i, j] = gram[i, j] + gmat = fpylll.IntegerMatrix.from_matrix(L.gram_matrix()) gso = fpylll.GSO.Mat(gmat, gram=True) ok = gso.update_gso() assert ok diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 834c1113874..f90cc912d97 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -65,7 +65,7 @@ A mixed integer linear program can give you an answer: The following example shows all these steps:: sage: p = MixedIntegerLinearProgram(maximization=False, solver='GLPK') - sage: w = p.new_variable(integer=True, nonnegative=True) + sage: w = p.new_variable(integer=True, nonnegative=True, name='w') sage: p.add_constraint(w[0] + w[1] + w[2] - 14*w[3] == 0) sage: p.add_constraint(w[1] + 2*w[2] - 8*w[3] == 0) sage: p.add_constraint(2*w[2] - 3*w[3] == 0) @@ -74,18 +74,18 @@ The following example shows all these steps:: sage: p.set_objective(w[3]) sage: p.show() Minimization: - x_3 + w[3] Constraints: - 0.0 <= x_0 + x_1 + x_2 - 14.0 x_3 <= 0.0 - 0.0 <= x_1 + 2.0 x_2 - 8.0 x_3 <= 0.0 - 0.0 <= 2.0 x_2 - 3.0 x_3 <= 0.0 - - x_0 + x_1 + x_2 <= 0.0 - - x_3 <= -1.0 + 0.0 <= w[0] + w[1] + w[2] - 14.0 w[3] <= 0.0 + 0.0 <= w[1] + 2.0 w[2] - 8.0 w[3] <= 0.0 + 0.0 <= 2.0 w[2] - 3.0 w[3] <= 0.0 + - w[0] + w[1] + w[2] <= 0.0 + - w[3] <= -1.0 Variables: - x_0 is an integer variable (min=0.0, max=+oo) - x_1 is an integer variable (min=0.0, max=+oo) - x_2 is an integer variable (min=0.0, max=+oo) - x_3 is an integer variable (min=0.0, max=+oo) + w[0] = x_0 is an integer variable (min=0.0, max=+oo) + w[1] = x_1 is an integer variable (min=0.0, max=+oo) + w[2] = x_2 is an integer variable (min=0.0, max=+oo) + w[3] = x_3 is an integer variable (min=0.0, max=+oo) sage: print('Objective Value: {}'.format(p.solve())) Objective Value: 2.0 sage: for i, v in sorted(p.get_values(w, convert=ZZ, tolerance=1e-3).items()): @@ -95,6 +95,34 @@ The following example shows all these steps:: w_2 = 3 w_3 = 2 +If your problem is already in the standard form, for example:: + + sage: A = matrix([[1, 2], [3, 5]]) + sage: b = vector([7, 11]) + sage: c = vector([5, 9]) + +You can add the constraint by treating the variable dictionary as a vector:: + + sage: p = MixedIntegerLinearProgram(maximization=True, solver='GLPK') + sage: w = p.new_variable(integer=True, name='w') + sage: p.add_constraint(A * w <= b) + sage: p.set_objective((c.row() * w)[0]) + sage: p.show() + Maximization: + 5.0 w[0] + 9.0 w[1] + Constraints: + w[0] + 2.0 w[1] <= 7.0 + 3.0 w[0] + 5.0 w[1] <= 11.0 + Variables: + w[0] = x_0 is an integer variable (min=-oo, max=+oo) + w[1] = x_1 is an integer variable (min=-oo, max=+oo) + sage: print('Objective Value: {}'.format(p.solve())) + Objective Value: 25.0 + sage: for i, v in sorted(p.get_values(w, convert=ZZ, tolerance=1e-3).items()): + ....: print(f'w_{i} = {v}') + w_0 = -13 + w_1 = 10 + Different backends compute with different base fields, for example:: sage: p = MixedIntegerLinearProgram(solver='GLPK') @@ -144,8 +172,6 @@ also allowed:: sage: a[4, 'string', QQ] - 7*b[2] x_2 - 7*x_3 sage: mip.show() - Maximization: - Constraints: Variables: a[1] = x_0 is a continuous variable (min=-oo, max=+oo) @@ -778,8 +804,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: p.add_constraint(x[0] + x[3] <= 8) sage: p.add_constraint(y[0] >= y[1]) sage: p.show() - Maximization: - Constraints: x_0 + x_1 <= 8.0 - x_2 + x_3 <= 0.0 @@ -795,8 +819,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: mip. = MixedIntegerLinearProgram(solver='GLPK') sage: mip.add_constraint(x[0] + y[1] + z[2] <= 10) sage: mip.show() - Maximization: - Constraints: x[0] + y[1] + z[2] <= 10.0 Variables: @@ -860,8 +882,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: a[0] + b[2] x_0 + x_1 sage: mip.show() - Maximization: - Constraints: Variables: a[0] = x_0 is a continuous variable (min=-oo, max=+oo) @@ -1251,23 +1271,24 @@ cdef class MixedIntegerLinearProgram(SageObject): varid_explainer[i] = varid_name[i] = default_name ##### Sense and objective function - print("Maximization:" if b.is_maximization() else "Minimization:") - print(" ", end=" ") + formula_parts = [] first = True for 0<= i< b.ncols(): c = b.objective_coefficient(i) if c == 0: continue - print((("+ " if (not first and c>0) else "") + - ("" if c == 1 else ("- " if c == -1 else str(c)+" "))+varid_name[i] - ), end=" ") + formula_parts.append(("+ " if (not first and c>0) else "") + + ("" if c == 1 else ("- " if c == -1 else str(c)+" "))+varid_name[i] + ) first = False d = b.objective_constant_term() if d > self._backend.zero(): - print("+ {} ".format(d)) + formula_parts.append("+ {}".format(d)) elif d < self._backend.zero(): - print("- {} ".format(-d)) - print("\n") + formula_parts.append("- {}".format(-d)) + if formula_parts: + print("Maximization:" if b.is_maximization() else "Minimization:") + print(" " + " ".join(formula_parts)) ##### Constraints print("Constraints:") @@ -2001,8 +2022,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: b = p.new_variable(nonnegative=True) sage: p.add_constraint(b[8] - b[15] <= 3*b[8] + 9) sage: p.show() - Maximization: - Constraints: -2.0 x_0 - x_1 <= 9.0 Variables: @@ -2043,8 +2062,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: for each in range(10): ....: lp.add_constraint(lp[0]-lp[1], min=1) sage: lp.show() - Maximization: - Constraints: 1.0 <= x_0 - x_1 Variables: @@ -2056,8 +2073,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: for each in range(10): ....: lp.add_constraint(2*lp[0] - 2*lp[1], min=2) sage: lp.show() - Maximization: - Constraints: 1.0 <= x_0 - x_1 Variables: @@ -2069,8 +2084,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: for each in range(10): ....: lp.add_constraint(-2*lp[0] + 2*lp[1], min=-2) sage: lp.show() - Maximization: - Constraints: 1.0 <= x_0 - x_1 -2.0 <= -2.0 x_0 + 2.0 x_1 @@ -2268,8 +2281,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: p.add_constraint(x - y, max=0) sage: p.add_constraint(x, max=4) sage: p.show() - Maximization: - Constraints: x_0 + x_1 <= 10.0 x_0 - x_1 <= 0.0 @@ -2277,8 +2288,6 @@ cdef class MixedIntegerLinearProgram(SageObject): ... sage: p.remove_constraint(1) sage: p.show() - Maximization: - Constraints: x_0 + x_1 <= 10.0 x_0 <= 4.0 @@ -2306,8 +2315,6 @@ cdef class MixedIntegerLinearProgram(SageObject): sage: p.add_constraint(x - y, max=0) sage: p.add_constraint(x, max=4) sage: p.show() - Maximization: - Constraints: x_0 + x_1 <= 10.0 x_0 - x_1 <= 0.0 @@ -2315,8 +2322,6 @@ cdef class MixedIntegerLinearProgram(SageObject): ... sage: p.remove_constraints([0, 1]) sage: p.show() - Maximization: - Constraints: x_0 <= 4.0 ... @@ -3627,8 +3632,19 @@ cdef class MIPVariable(FiniteFamily): (1, 1/2)*x_0 + (2/3, 3/4)*x_1 sage: m * v (1, 2/3)*x_0 + (1/2, 3/4)*x_1 + + sage: c = vector([1, 2]) + sage: v * c + x_0 + 2*x_1 + sage: c * v + x_0 + 2*x_1 """ + from sage.structure.element import Vector + if isinstance(left, Vector): + left, right = right, left if isinstance(left, MIPVariable): + if isinstance(right, Vector): + return ( left)._matrix_rmul_impl(right.column())[0] if not isinstance(right, Matrix): return NotImplemented return ( left)._matrix_rmul_impl(right) diff --git a/src/sage/quadratic_forms/bqf_class_group.py b/src/sage/quadratic_forms/bqf_class_group.py index d1eb9683ddd..ac896d33f1f 100644 --- a/src/sage/quadratic_forms/bqf_class_group.py +++ b/src/sage/quadratic_forms/bqf_class_group.py @@ -56,7 +56,8 @@ sage: cl2 * cl2.order() == Cl.zero() True sage: Cl.abelian_group() - Additive abelian group isomorphic to Z/21 embedded in Form Class Group of Discriminant -431 + Additive abelian group isomorphic to Z/21 embedded in + Form Class Group of Discriminant -431 sage: Cl.gens() # random [Class of 5*x^2 + 3*x*y + 22*y^2] sage: Cl.gens()[0].order() @@ -86,11 +87,8 @@ from sage.misc.prandom import randrange from sage.rings.integer_ring import ZZ -from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.finite_rings.integer_mod import Mod -from sage.rings.polynomial.polynomial_ring import polygen from sage.arith.misc import random_prime -from sage.matrix.constructor import matrix from sage.groups.generic import order_from_multiple, multiple from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper from sage.quadratic_forms.binary_qf import BinaryQF @@ -124,7 +122,7 @@ class BQFClassGroup(Parent, UniqueRepresentation): Form Class Group of Discriminant -484 """ - def __init__(self, D, *, check=True): + def __init__(self, D, *, check=True) -> None: r""" Construct the class group for a given discriminant `D`. @@ -159,7 +157,8 @@ def _element_constructor_(self, F, *, check=True): Class of 16*x^2 + 5*x*y + 16*y^2 """ if isinstance(F, BQFClassGroup_element): - if check and F.parent() is not self: # class group is unique parent + if check and F.parent() is not self: + # class group is unique parent raise ValueError('quadratic form has incorrect discriminant') return F if F == 0: @@ -170,8 +169,10 @@ def _element_constructor_(self, F, *, check=True): def zero(self): r""" - Return the neutral element of this group, i.e., the class of the - principal binary quadratic form of the respective discriminant. + Return the neutral element of this group. + + This is the class of the principal binary quadratic form of + the respective discriminant. EXAMPLES:: @@ -219,7 +220,7 @@ def random_element(self): b = -b return self(BinaryQF([a, b, c])) - def __hash__(self): + def __hash__(self) -> int: r""" Return a hash value for this form class group. @@ -230,7 +231,7 @@ def __hash__(self): """ return hash(('BQFClassGroup', self._disc)) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string describing this form class group. @@ -299,7 +300,8 @@ def abelian_group(self): sage: Cl.order() 16 sage: G = Cl.abelian_group(); G - Additive abelian group isomorphic to Z/4 + Z/2 + Z/2 embedded in Form Class Group of Discriminant -3108 + Additive abelian group isomorphic to Z/4 + Z/2 + Z/2 embedded in + Form Class Group of Discriminant -3108 sage: G.gens() # random (Class of 11*x^2 + 4*x*y + 71*y^2, Class of 6*x^2 + 6*x*y + 131*y^2, @@ -314,7 +316,7 @@ def abelian_group(self): gens = [BinaryQF(g) for g in gens] return AdditiveAbelianGroupWrapper(self, gens, ords) - def gens(self) -> list: + def gens(self) -> tuple: r""" Return a generating set of this form class group. @@ -322,17 +324,17 @@ def gens(self) -> list: sage: Cl = BQFClassGroup(-4*419) sage: Cl.gens() - [Class of 3*x^2 + 2*x*y + 140*y^2] + (Class of 3*x^2 + 2*x*y + 140*y^2,) :: sage: Cl = BQFClassGroup(-4*777) sage: Cl.gens() # random - [Class of 11*x^2 + 4*x*y + 71*y^2, + (Class of 11*x^2 + 4*x*y + 71*y^2, Class of 6*x^2 + 6*x*y + 131*y^2, - Class of 2*x^2 + 2*x*y + 389*y^2] + Class of 2*x^2 + 2*x*y + 389*y^2) """ - return [g.element() for g in self.abelian_group().gens()] + return tuple(g.element() for g in self.abelian_group().gens()) def _coerce_map_from_(self, other): r""" @@ -345,7 +347,7 @@ def _coerce_map_from_(self, other): sage: G = BQFClassGroup(-4*117117) sage: H = BQFClassGroup(-4*77) - sage: proj = G.hom(H); proj # implicit doctest + sage: proj = G.hom(H); proj # indirect doctest Coercion morphism: From: Form Class Group of Discriminant -468468 To: Form Class Group of Discriminant -308 @@ -376,7 +378,7 @@ class BQFClassGroup_element(AdditiveGroupElement): EXAMPLES:: sage: F = BinaryQF([22, 91, 99]) - sage: F.form_class() # implicit doctest + sage: F.form_class() # indirect doctest Class of 5*x^2 - 3*x*y + 22*y^2 :: @@ -384,11 +386,11 @@ class BQFClassGroup_element(AdditiveGroupElement): sage: Cl = BQFClassGroup(-4*419) sage: Cl.zero() Class of x^2 + 419*y^2 - sage: Cl.gens()[0] # implicit doctest + sage: Cl.gens()[0] # indirect doctest Class of 3*x^2 + 2*x*y + 140*y^2 """ - def __init__(self, F, parent, *, check=True, reduce=True): + def __init__(self, F, parent, *, check=True, reduce=True) -> None: r""" Constructor for classes of binary quadratic forms. @@ -515,7 +517,7 @@ def __mul__(self, other): __rmul__ = __mul__ - def __eq__(self, other): + def __eq__(self, other) -> bool: r""" Test two form classes for equality. @@ -535,7 +537,7 @@ def __eq__(self, other): # as well as hashing. return self._form == other._form - def __ne__(self, other): + def __ne__(self, other) -> bool: r""" Test two form classes for inequality. @@ -551,7 +553,7 @@ def __ne__(self, other): """ return self._form != other._form - def __lt__(self, other): + def __lt__(self, other) -> bool: r""" Compare two form classes according to the lexicographic ordering on their coefficient lists. @@ -599,7 +601,7 @@ def is_zero(self) -> bool: """ return not self - def __repr__(self) -> str: + def _repr_(self) -> str: r""" Return a string representation of this form class. @@ -611,7 +613,7 @@ def __repr__(self) -> str: """ return f'Class of {self._form}' - def __hash__(self): + def __hash__(self) -> int: r""" Return a hash value for this form class. @@ -698,7 +700,7 @@ class representative `[a,b,c]` satisfying `f^2 \mid a` and `f \mid b` sage: proj(elt) == proj2(proj1(elt)) True """ - def __init__(self, G, H): + def __init__(self, G, H) -> None: r""" Initialize this morphism between class groups of binary quadratic forms. diff --git a/src/sage/rings/finite_rings/hom_finite_field.pyx b/src/sage/rings/finite_rings/hom_finite_field.pyx index 9e825650fca..3ee3adde425 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field.pyx @@ -439,7 +439,7 @@ cdef class FiniteFieldHomomorphism_generic(RingHomomorphism_im_gens): sage: Frob = k.frobenius_endomorphism() sage: embed = Frob.fixed_field()[1] sage: embed.__reduce__() # indirect doctest - (, + (, (, Set of field embeddings from Finite Field of size 5 to Finite Field in t of size 5^3, {}, diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 401b2144be9..c46a231a21d 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -122,19 +122,6 @@ sage: m(y)^2 + m(y) + m(x) + 1/m(x) # long time (8s) O(s^5) -TESTS:: - - sage: TestSuite(J).run() - sage: TestSuite(K).run(max_runs=256) # long time (10s) # needs sage.rings.function_field sage.rings.number_field - sage: TestSuite(L).run(max_runs=8) # long time (25s) # needs sage.rings.function_field sage.rings.number_field - - sage: # needs sage.rings.finite_rings sage.rings.function_field - sage: TestSuite(M).run(max_runs=8) # long time (35s) - sage: TestSuite(N).run(max_runs=8, skip='_test_derivation') # long time (15s) - sage: TestSuite(O).run() - sage: TestSuite(R).run() - sage: TestSuite(S).run() # long time (4s) - Global function fields ---------------------- @@ -301,10 +288,12 @@ def __init__(self, base_field, names, category=FunctionFields()): """ Initialize. - TESTS:: + EXAMPLES:: + + sage: K = FunctionField(QQ, 'z') + sage: K + Rational function field in z over Rational Field - sage: K. = FunctionField(QQ) - sage: TestSuite(K).run() # long time (3s) """ Field.__init__(self, base_field, names=names, category=category) @@ -747,7 +736,8 @@ def _test_derivation(self, **options): EXAMPLES:: sage: K. = FunctionField(QQ) - sage: TestSuite(K).run() # indirect doctest, long time (3s) + sage: K._test_derivation() # long time + """ tester = self._tester(**options) S = tester.some_elements() diff --git a/src/sage/rings/function_field/function_field_test.py b/src/sage/rings/function_field/function_field_test.py new file mode 100644 index 00000000000..e8a1359eadf --- /dev/null +++ b/src/sage/rings/function_field/function_field_test.py @@ -0,0 +1,116 @@ +import pytest + +from sage.rings.finite_rings.finite_field_constructor import FiniteField +from sage.rings.function_field.constructor import FunctionField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ + + +@pytest.fixture +def F(): + return FunctionField(QQ, 'x') + + +@pytest.fixture +def J(): + return FunctionField(FiniteField(5), 'x') + + +@pytest.fixture +def K(): + return FunctionField(FiniteField(5**2,'a'), 'x') + + +@pytest.fixture +def L(F): + x = F.gen() + Y = PolynomialRing(F, 'Y').gen() + return F.extension(Y**2 + Y + x + 1/x, 'y') + + +@pytest.fixture +def M(K, R, S): + x = K.gen() + y = R.gen() + L = K.extension(y**3 - (x**3 + 2*x*y + 1/x)) + t = S.gen() + return L.extension(t**2 - x*y) + + +@pytest.fixture +def N(K): + return FunctionField(K, 'u') + + +@pytest.fixture +def O(L): + return L.maximal_order() + + +@pytest.fixture +def R(K): + return PolynomialRing(K, 'y') + + +@pytest.fixture +def S(K, R): + x = K.gen() + y = R.gen() + L = K.extension(y**3 - (x**3 + 2*x*y + 1/x)) + return PolynomialRing(L, 't') + + +@pytest.fixture +def T(F): + return PolynomialRing(F, 'Y') + + +# Use strings for the fixture names here, and then later convert them +# to the actual fixture objects using request.getfixturevalue(). This +# is a workaround for being unable to pass fixtures directly as +# parameters: +# +# https://github.com/pytest-dev/pytest/issues/349 +# +pairs = [ ("J", None), + ("K", 16), + ("L", 2), + ("M", 1), + ("N", 1), + ("O", None), + ("T", None), + ("S", 8) ] + + +@pytest.mark.parametrize("ff,max_runs", pairs) +def test_function_field_testsuite(ff, max_runs, request): + r""" + Run the TestSuite() on some function fields that are + constructed in the documentation. They are slow, random, and not + intended for end users. All of this makes them more appropriate to + be run separately, here, than in the doctests. + + INPUT: + + The inputs are essentially all fixtures. + + - ``ff`` -- string; a function field fixture name + - ``max_runs`` -- integer; the maxmimum number of times to + repeat the test suite + - ``request`` -- fixture; a pytest built-in + + """ + # The sage.misc.sage_unittest.TestSuite import is local to avoid + # pytest warnings. + from sage.misc.sage_unittest import TestSuite + + # Convert the fixture name (string) to an actual object using the + # built-in "request" fixture. + ff = request.getfixturevalue(ff) + + # Pass max_runs only if it's not None; otherwise use the default + run_args = { "verbose": True, "raise_on_failure": True } + if max_runs: + run_args["max_runs"] = max_runs + + TestSuite(ff).run(**run_args) diff --git a/src/sage/rings/function_field/meson.build b/src/sage/rings/function_field/meson.build index 0ed61989167..6fc7af00954 100644 --- a/src/sage/rings/function_field/meson.build +++ b/src/sage/rings/function_field/meson.build @@ -12,6 +12,7 @@ py.install_sources( 'function_field.py', 'function_field_polymod.py', 'function_field_rational.py', + 'function_field_test.py', 'ideal.py', 'ideal_polymod.py', 'ideal_rational.py', diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index 53e793755ec..e0e5057d463 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -286,14 +286,14 @@ cdef class DisjointSet_class(SageObject): sage: d = DisjointSet(5) sage: d.__reduce__() - (, (5,), [0, 1, 2, 3, 4]) + (, (5,), [0, 1, 2, 3, 4]) :: sage: d.union(2, 4) sage: d.union(1, 3) sage: d.__reduce__() - (, (5,), [0, 1, 2, 1, 2]) + (, (5,), [0, 1, 2, 1, 2]) """ return DisjointSet, (self._nodes.degree,), self.__getstate__() @@ -730,7 +730,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): {{0}, {1}, {2}, {3}, {4}} sage: d = _ sage: d.__reduce__() - (, + (, ([0, 1, 2, 3, 4],), [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]) @@ -739,7 +739,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): sage: d.union(2, 4) sage: d.union(1, 3) sage: d.__reduce__() - (, + (, ([0, 1, 2, 3, 4],), [(0, 0), (1, 1), (2, 2), (3, 1), (4, 2)]) """ diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 8571811dd97..aaf0c285322 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -583,7 +583,7 @@ cdef class CategoryObject(SageObject): sage: F.base_ring() # needs sage.modules Integer Ring sage: F.__class__.base_ring # needs sage.modules - + Note that the coordinates of the elements of a module can lie in a bigger ring, the ``coordinate_ring``:: @@ -604,7 +604,7 @@ cdef class CategoryObject(SageObject): sage: F.base_ring() # needs sage.combinat sage.modules Rational Field sage: F.__class__.base_ring # needs sage.combinat sage.modules - + sage: # needs sage.modules sage: E = CombinatorialFreeModule(ZZ, [1,2,3]) @@ -613,7 +613,7 @@ cdef class CategoryObject(SageObject): sage: H.base_ring() Integer Ring sage: H.__class__.base_ring - + .. TODO:: diff --git a/src/sage/structure/factory.pyx b/src/sage/structure/factory.pyx index bde82e5d18f..31b8e1ac707 100644 --- a/src/sage/structure/factory.pyx +++ b/src/sage/structure/factory.pyx @@ -555,7 +555,7 @@ cdef class UniqueFactory(SageObject): sage: a = test_factory(1, 2) Making object (1, 2) sage: test_factory.reduce_data(a) - (, + (, (, (...), (1, 2), diff --git a/src/sage/structure/list_clone.pyx b/src/sage/structure/list_clone.pyx index 03c0cd23530..a084b221f10 100644 --- a/src/sage/structure/list_clone.pyx +++ b/src/sage/structure/list_clone.pyx @@ -933,7 +933,7 @@ cdef class ClonableArray(ClonableElement): sage: loads(dumps(el)) [1, 2, 4] sage: t = el.__reduce__(); t - (, + (, (, , [1, 2, 4], @@ -1729,7 +1729,7 @@ cdef class ClonableIntArray(ClonableElement): sage: loads(dumps(el)) [1, 2, 4] sage: t = el.__reduce__(); t - (, + (, (, , [1, 2, 4], diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index b4933c6fe6a..dc59841b816 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -14194,3 +14194,15 @@ include "pynac_constant_impl.pxi" include "pynac_function_impl.pxi" include "series_impl.pxi" include "substitution_map_impl.pxi" + + +# ------------------------------------------------------------ +# Trac #26254: Inject symbolic-function-related functions into +# sage.symbolic.function +# ------------------------------------------------------------ +import sage.symbolic.function +sage.symbolic.function.call_registered_function = call_registered_function +sage.symbolic.function.find_registered_function = find_registered_function +sage.symbolic.function.register_or_update_function = register_or_update_function +sage.symbolic.function.get_sfunction_from_hash = get_sfunction_from_hash +sage.symbolic.function.get_sfunction_from_serial = get_sfunction_from_serial diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index fa2c5e209eb..22843aa7bb9 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -143,9 +143,10 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.structure.parent cimport Parent from sage.structure.coerce cimport (coercion_model, - py_scalar_to_element, is_numpy_type, is_mpmath_type) + py_scalar_to_element, + is_numpy_type, is_mpmath_type) from sage.structure.richcmp cimport richcmp - +from sage.misc.lazy_attribute import lazy_attribute from sage.misc.fpickle import pickle_function, unpickle_function from sage.symbolic.symbols import symbol_table, register_symbol @@ -165,6 +166,7 @@ cdef object SR = None, PolynomialRing_commutative = None, MPolynomialRing_polydi sfunctions_funcs = ['eval', 'evalf', 'conjugate', 'real_part', 'imag_part', 'derivative', 'power', 'series', 'print', 'print_latex', 'tderivative'] + cdef class Function(SageObject): """ Base class for symbolic functions defined through Pynac in Sage. @@ -270,6 +272,7 @@ cdef class Function(SageObject): sage: deepcopy(f) f(x) """ + from .expression import register_or_update_function self._serial = register_or_update_function(self, self._name, self._latex_name, self._nargs, self._evalf_params_first, False) @@ -551,6 +554,7 @@ cdef class Function(SageObject): if not isinstance(a, Expression): raise TypeError("arguments must be symbolic expressions") + from .expression import call_registered_function return call_registered_function(self._serial, self._nargs, args, hold, not symbolic_input, SR) @@ -849,6 +853,7 @@ cdef class GinacFunction(BuiltinFunction): preserved_arg=preserved_arg, alt_name=alt_name) cdef _is_registered(self): + from .expression import find_registered_function, get_sfunction_from_serial # Since this is function is defined in C++, it is already in # ginac's function registry fname = self._ginac_name if self._ginac_name is not None else self._name @@ -856,6 +861,7 @@ cdef class GinacFunction(BuiltinFunction): return bool(get_sfunction_from_serial(self._serial)) cdef _register_function(self): + from .expression import register_or_update_function # We don't need to add anything to GiNaC's function registry # However, if any custom methods were provided in the python class, # we should set the properties of the function_options object @@ -1121,6 +1127,7 @@ cdef class BuiltinFunction(Function): sage: loads(dumps(cot)) == cot # Issue #15138 True """ + from .expression import find_registered_function, get_sfunction_from_serial # check if already defined cdef unsigned int serial @@ -1218,6 +1225,7 @@ cdef class SymbolicFunction(Function): evalf_params_first) cdef _is_registered(SymbolicFunction self): + from .expression import get_sfunction_from_hash # see if there is already a SymbolicFunction with the same state cdef long myhash = self._hash_() cdef SymbolicFunction sfunc = get_sfunction_from_hash(myhash) diff --git a/src/sage/symbolic/getitem_impl.pxi b/src/sage/symbolic/getitem_impl.pxi index cbc5f6b9c97..5d0bfc12bba 100644 --- a/src/sage/symbolic/getitem_impl.pxi +++ b/src/sage/symbolic/getitem_impl.pxi @@ -182,7 +182,7 @@ cdef class OperandsWrapper(SageObject): TESTS:: sage: (x^2).op.__reduce__() - (, (x^2,)) + (, (x^2,)) sage: loads(dumps((x^2).op)) Operands of x^2 """ diff --git a/src/sage/symbolic/pynac_function_impl.pxi b/src/sage/symbolic/pynac_function_impl.pxi index ca2b459e095..351300154b6 100644 --- a/src/sage/symbolic/pynac_function_impl.pxi +++ b/src/sage/symbolic/pynac_function_impl.pxi @@ -179,7 +179,7 @@ cpdef get_sfunction_from_serial(unsigned int serial): EXAMPLES:: - sage: from sage.symbolic.function import get_sfunction_from_serial + sage: from sage.symbolic.expression import get_sfunction_from_serial sage: get_sfunction_from_serial(65) #random f """ diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index 34404ce0d66..47c470118b8 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -273,8 +273,7 @@ def get_fn_serial(): EXAMPLES:: - sage: from sage.symbolic.expression import get_fn_serial - sage: from sage.symbolic.function import get_sfunction_from_serial + sage: from sage.symbolic.expression import get_fn_serial, get_sfunction_from_serial sage: get_fn_serial() > 125 True sage: print(get_sfunction_from_serial(get_fn_serial())) @@ -452,8 +451,7 @@ def py_print_function_pystring(id, args, fname_paren=False): EXAMPLES:: - sage: from sage.symbolic.expression import py_print_function_pystring, get_ginac_serial, get_fn_serial - sage: from sage.symbolic.function import get_sfunction_from_serial + sage: from sage.symbolic.expression import py_print_function_pystring, get_ginac_serial, get_fn_serial, get_sfunction_from_serial sage: var('x,y,z') (x, y, z) sage: foo = function('foo', nargs=2) @@ -516,8 +514,7 @@ def py_latex_function_pystring(id, args, fname_paren=False): EXAMPLES:: - sage: from sage.symbolic.expression import py_latex_function_pystring, get_ginac_serial, get_fn_serial - sage: from sage.symbolic.function import get_sfunction_from_serial + sage: from sage.symbolic.expression import py_latex_function_pystring, get_ginac_serial, get_fn_serial, get_sfunction_from_serial sage: var('x,y,z') (x, y, z) sage: foo = function('foo', nargs=2) @@ -652,10 +649,9 @@ def py_print_fderivative_for_doctests(id, params, args): EXAMPLES:: - sage: from sage.symbolic.expression import py_print_fderivative_for_doctests as py_print_fderivative, get_ginac_serial, get_fn_serial + sage: from sage.symbolic.expression import py_print_fderivative_for_doctests as py_print_fderivative, get_ginac_serial, get_fn_serial, get_sfunction_from_serial sage: var('x,y,z') (x, y, z) - sage: from sage.symbolic.function import get_sfunction_from_serial sage: foo = function('foo', nargs=2) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break @@ -728,11 +724,9 @@ def py_latex_fderivative_for_doctests(id, params, args): EXAMPLES:: - sage: from sage.symbolic.expression import py_latex_fderivative_for_doctests as py_latex_fderivative, get_ginac_serial, get_fn_serial - + sage: from sage.symbolic.expression import py_latex_fderivative_for_doctests as py_latex_fderivative, get_ginac_serial, get_fn_serial, get_sfunction_from_serial sage: var('x,y,z') (x, y, z) - sage: from sage.symbolic.function import get_sfunction_from_serial sage: foo = function('foo', nargs=2) sage: for i in range(get_ginac_serial(), get_fn_serial()): ....: if get_sfunction_from_serial(i) == foo: break diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index 795704a70ef..eecf2a98f33 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -430,8 +430,7 @@ def check_symbolic_expression_order(repetitions=100): EXAMPLES:: sage: from sage.symbolic.random_tests import check_symbolic_expression_order - sage: check_symbolic_expression_order(200) - sage: check_symbolic_expression_order(10000) # long time + sage: check_symbolic_expression_order(500) # long time """ rnd_length = 50 nvars = 10 diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 4d0aa37a159..2ed691eff0f 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -52,8 +52,11 @@ from sage.structure.coerce cimport is_numpy_type import sage.rings.abc from sage.rings.integer_ring import ZZ -# is_SymbolicVariable used to be defined here; re-export it -from sage.symbolic.expression import _is_SymbolicVariable as is_SymbolicVariable +# is_SymbolicVariable used to be defined here; re-export it here lazily +cpdef bint is_SymbolicVariable(x): + from sage.symbolic.expression import _is_SymbolicVariable + + return _is_SymbolicVariable(x) import keyword import operator diff --git a/src/sage/version.py b/src/sage/version.py index bab97a1c6a8..73695a89cad 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the update-version script, do not edit! -version = '10.7.beta9' -date = '2025-07-25' -banner = 'SageMath version 10.7.beta9, Release Date: 2025-07-25' +version = '10.7.rc0' +date = '2025-08-02' +banner = 'SageMath version 10.7.rc0, Release Date: 2025-08-02' diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index d62ff8b87d1..c62cddaf486 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -39,6 +39,8 @@ - François Bissey (2024-11-12): rebased on Sphinx 8.1.3 (while trying to keep python 3.9 compatibility) - François Bissey (2025-02-24): Remove python 3.9 support hacks, making us closer to upstream + +- François Bissey (2025-03-18): rebased on sphinx 8.2.3 """ from __future__ import annotations @@ -46,13 +48,14 @@ import functools import operator import re +import sys from inspect import Parameter, Signature from typing import TYPE_CHECKING, Any, NewType, TypeVar from docutils.statemachine import StringList import sphinx -from sphinx.config import ENUM, Config +from sphinx.config import ENUM from sphinx.errors import PycodeError from sphinx.ext.autodoc.importer import get_class_members, import_module, import_object from sphinx.ext.autodoc.mock import ismock, mock, undecorate @@ -67,13 +70,7 @@ safe_getattr, stringify_signature, ) -from sphinx.util.typing import ( - ExtensionMetadata, - OptionSpec, - get_type_hints, - restify, - stringify_annotation, -) +from sphinx.util.typing import get_type_hints, restify, stringify_annotation # ------------------------------------------------------------------ from sage.misc.sageinspect import (sage_getdoc_original, @@ -96,8 +93,12 @@ def getdoc(obj, *args, **kwargs): from typing import ClassVar, Literal, TypeAlias from sphinx.application import Sphinx - from sphinx.environment import BuildEnvironment + from sphinx.config import Config + from sphinx.environment import BuildEnvironment, _CurrentDocument + from sphinx.events import EventManager from sphinx.ext.autodoc.directive import DocumenterBridge + from sphinx.registry import SphinxComponentRegistry + from sphinx.util.typing import ExtensionMetadata, OptionSpec, _RestifyMode _AutodocObjType = Literal[ 'module', 'class', 'exception', 'function', 'method', 'attribute' @@ -117,26 +118,35 @@ def getdoc(obj, *args, **kwargs): # As of Sphinx 7.2.6, Sphinx is confused with unquoted "::" in the comment # below. # ------------------------------------------------------------------------ - #: extended signature RE: with explicit module name separated by "::" py_ext_sig_re = re.compile( - r'''^ ([\w.]+::)? # explicit module name + r"""^ ([\w.]+::)? # explicit module name ([\w.]+\.)? # module and/or class name(s) (\w+) \s* # thing name - (?: \[\s*(.*)\s*])? # optional: type parameters list + (?: \[\s*(.*?)\s*])? # optional: type parameters list (?: \((.*)\) # optional: arguments (?:\s* -> \s* (.*))? # return annotation )? $ # and nothing more - ''', re.VERBOSE) + """, + re.VERBOSE, +) special_member_re = re.compile(r'^__\S+__$') +def _get_render_mode( + typehints_format: Literal['fully-qualified', 'short'], +) -> _RestifyMode: + if typehints_format == 'short': + return 'smart' + return 'fully-qualified-except-typing' + + def identity(x: Any) -> Any: return x class _All: - r"""A special value for :\*-members: that matches to any member.""" + """A special value for :*-members: that matches to any member.""" def __contains__(self, item: Any) -> bool: return True @@ -161,7 +171,7 @@ def __contains__(self, item: Any) -> bool: def members_option(arg: Any) -> object | list[str]: """Used to convert the :members: option to auto directives.""" - if arg in (None, True): + if arg in {None, True}: return ALL elif arg is False: return None @@ -171,14 +181,14 @@ def members_option(arg: Any) -> object | list[str]: def exclude_members_option(arg: Any) -> object | set[str]: """Used to convert the :exclude-members: option.""" - if arg in (None, True): + if arg in {None, True}: return EMPTY return {x.strip() for x in arg.split(',') if x.strip()} def inherited_members_option(arg: Any) -> set[str]: """Used to convert the :inherited-members: option to auto directives.""" - if arg in (None, True): + if arg in {None, True}: return {'object'} elif arg: return {x.strip() for x in arg.split(',')} @@ -188,9 +198,9 @@ def inherited_members_option(arg: Any) -> set[str]: def member_order_option(arg: Any) -> str | None: """Used to convert the :member-order: option to auto directives.""" - if arg in (None, True): + if arg in {None, True}: return None - elif arg in ('alphabetical', 'bysource', 'groupwise'): + elif arg in {'alphabetical', 'bysource', 'groupwise'}: return arg else: raise ValueError(__('invalid value for member-order option: %s') % arg) @@ -198,7 +208,7 @@ def member_order_option(arg: Any) -> str | None: def class_doc_from_option(arg: Any) -> str | None: """Used to convert the :class-doc-from: option to autoclass directives.""" - if arg in ('both', 'class', 'init'): + if arg in {'both', 'class', 'init'}: return arg else: raise ValueError(__('invalid value for class-doc-from option: %s') % arg) @@ -208,7 +218,7 @@ def class_doc_from_option(arg: Any) -> str | None: def annotation_option(arg: Any) -> Any: - if arg in (None, True): + if arg in {None, True}: # suppress showing the representation of the object return SUPPRESS else: @@ -222,7 +232,7 @@ def bool_option(arg: Any) -> bool: return True -def merge_members_option(options: dict) -> None: +def merge_members_option(options: dict[str, Any]) -> None: """Merge :private-members: and :special-members: options to the :members: option. """ @@ -232,14 +242,16 @@ def merge_members_option(options: dict) -> None: members = options.setdefault('members', []) for key in ('private-members', 'special-members'): - if key in options and options[key] not in (ALL, None): - for member in options[key]: + other_members = options.get(key) + if other_members is not None and other_members is not ALL: + for member in other_members: if member not in members: members.append(member) # Some useful event listener factories for autodoc-process-docstring. + def cut_lines( pre: int, post: int = 0, what: Sequence[str] | None = None ) -> _AutodocProcessDocstringListener: @@ -250,6 +262,7 @@ def cut_lines( Use like this (e.g. in the ``setup()`` function of :file:`conf.py`):: from sphinx.ext.autodoc import cut_lines + app.connect('autodoc-process-docstring', cut_lines(4, what={'module'})) This can (and should) be used in place of ``automodule_skip_lines``. @@ -293,6 +306,7 @@ def process( # make sure there is a blank line at the end if lines and lines[-1]: lines.append('') + return process @@ -339,12 +353,14 @@ def process( # make sure there is a blank line at the end if lines and lines[-1]: lines.append('') + return process # This class is used only in ``sphinx.ext.autodoc.directive``, -# But we define this class here to keep compatibility (see #4538) -class Options(dict[str, Any]): +# But we define this class here to keep compatibility +# See: https://github.com/sphinx-doc/sphinx/issues/4538 +class Options(dict[str, Any]): # NoQA: FURB189 """A dict/attribute hybrid that returns None on nonexisting keys.""" def copy(self) -> Options: @@ -364,18 +380,43 @@ class ObjectMember: represent each member of the object. """ - def __init__(self, name: str, obj: Any, *, docstring: str | None = None, - class_: Any = None, skipped: bool = False) -> None: + __slots__ = '__name__', 'object', 'docstring', 'class_', 'skipped' + + __name__: str + object: Any + docstring: str | None + class_: Any + skipped: bool + + def __init__( + self, + name: str, + obj: Any, + *, + docstring: str | None = None, + class_: Any = None, + skipped: bool = False, + ) -> None: self.__name__ = name self.object = obj self.docstring = docstring - self.skipped = skipped self.class_ = class_ + self.skipped = skipped + + def __repr__(self) -> str: + return ( + f'ObjectMember(' + f'name={self.__name__!r}, ' + f'obj={self.object!r}, ' + f'docstring={self.docstring!r}, ' + f'class_={self.class_!r}, ' + f'skipped={self.skipped!r}' + f')' + ) class Documenter: - """ - A Documenter knows how to autodocument a single object type. When + """A Documenter knows how to autodocument a single object type. When registered with the AutoDirective, it will be used to document objects of that type when needed by autodoc. @@ -403,25 +444,30 @@ class Documenter: option_spec: ClassVar[OptionSpec] = { 'no-index': bool_option, + 'no-index-entry': bool_option, 'noindex': bool_option, } def get_attr(self, obj: Any, name: str, *defargs: Any) -> Any: """getattr() override for types such as Zope interfaces.""" - return autodoc_attrgetter(self.env.app, obj, name, *defargs) + return autodoc_attrgetter(obj, name, *defargs, registry=self.env._registry) @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: """Called to see if a member can be documented by this Documenter.""" msg = 'must be implemented in subclasses' raise NotImplementedError(msg) - def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: + def __init__( + self, directive: DocumenterBridge, name: str, indent: str = '' + ) -> None: self.directive = directive self.config: Config = directive.env.config self.env: BuildEnvironment = directive.env + self._current_document: _CurrentDocument = directive.env.current_document + self._events: EventManager = directive.env.events self.options = directive.genopt self.name = name self.indent = indent @@ -446,7 +492,7 @@ def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> @property def documenters(self) -> dict[str, type[Documenter]]: """Returns registered Documenter classes""" - return self.env.app.registry.documenters + return self.env._registry.documenters def add_line(self, line: str, source: str, *lineno: int) -> None: """Append one line of generated reST to the output.""" @@ -455,8 +501,9 @@ def add_line(self, line: str, source: str, *lineno: int) -> None: else: self.directive.result.append('', source, *lineno) - def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, - ) -> tuple[str | None, list[str]]: + def resolve_name( + self, modname: str | None, parents: Any, path: str, base: str + ) -> tuple[str | None, list[str]]: """Resolve the module and name of the object to document given by the arguments and the current module/class. @@ -478,8 +525,12 @@ def parse_name(self) -> bool: # an autogenerated one matched = py_ext_sig_re.match(self.name) if matched is None: - logger.warning(__('invalid signature for auto%s (%r)'), self.objtype, self.name, - type='autodoc') + logger.warning( + __('invalid signature for auto%s (%r)'), + self.objtype, + self.name, + type='autodoc', + ) return False explicit_modname, path, base, tp_list, args, retann = matched.groups() @@ -500,8 +551,7 @@ def parse_name(self) -> bool: self.modname = modname self.args = args self.retann = retann - self.fullname = ((self.modname or '') + - ('.' + '.'.join(self.objpath) if self.objpath else '')) + self.fullname = '.'.join((self.modname or '', *self.objpath)) return True def import_object(self, raiseerror: bool = False) -> bool: @@ -513,8 +563,7 @@ def import_object(self, raiseerror: bool = False) -> bool: with mock(self.config.autodoc_mock_imports): try: ret = import_object( - self.modname, self.objpath, self.objtype, - attrgetter=self.get_attr, + self.modname, self.objpath, self.objtype, attrgetter=self.get_attr ) self.module, self.parent, self.object_name, self.object = ret if ismock(self.object): @@ -582,7 +631,7 @@ def format_signature(self, **kwargs: Any) -> str: """ if self.args is not None: # signature given explicitly - args = "(%s)" % self.args + args = f'({self.args})' retann = self.retann else: # try to introspect the signature @@ -595,13 +644,23 @@ def format_signature(self, **kwargs: Any) -> str: args = matched.group(1) retann = matched.group(2) except Exception as exc: - logger.warning(__('error while formatting arguments for %s: %s'), - self.fullname, exc, type='autodoc') + logger.warning( + __('error while formatting arguments for %s: %s'), + self.fullname, + exc, + type='autodoc', + ) args = None - result = self.env.events.emit_firstresult('autodoc-process-signature', - self.objtype, self.fullname, - self.object, self.options, args, retann) + result = self._events.emit_firstresult( + 'autodoc-process-signature', + self.objtype, + self.fullname, + self.object, + self.options, + args, + retann, + ) if result: args, retann = result @@ -619,14 +678,15 @@ def add_directive_header(self, sig: str) -> None: # one signature per line, indented by column prefix = f'.. {domain}:{directive}:: ' - for i, sig_line in enumerate(sig.split("\n")): - self.add_line(f'{prefix}{name}{sig_line}', - sourcename) + for i, sig_line in enumerate(sig.split('\n')): + self.add_line(f'{prefix}{name}{sig_line}', sourcename) if i == 0: - prefix = " " * len(prefix) + prefix = ' ' * len(prefix) if self.options.no_index or self.options.noindex: self.add_line(' :no-index:', sourcename) + if self.options.no_index_entry: + self.add_line(' :no-index-entry:', sourcename) if self.objpath: # Be explicit about the module, this is necessary since .. class:: # etc. don't support a prepended module name @@ -638,8 +698,13 @@ def get_doc(self) -> list[list[str]] | None: When it returns None, autodoc-process-docstring will not be called for this object. """ - docstring = getdoc(self.object, self.get_attr, self.config.autodoc_inherit_docstrings, - self.parent, self.object_name) + docstring = getdoc( + self.object, + self.get_attr, + self.config.autodoc_inherit_docstrings, + self.parent, + self.object_name, + ) if docstring: tab_width = self.directive.state.document.settings.tab_width return [prepare_docstring(docstring, tab_width)] @@ -648,21 +713,27 @@ def get_doc(self) -> list[list[str]] | None: def process_doc(self, docstrings: list[list[str]]) -> Iterator[str]: """Let the user process the docstrings before adding them.""" for docstringlines in docstrings: - if self.env.app: + if self._events is not None: # let extensions preprocess docstrings - self.env.app.emit('autodoc-process-docstring', - self.objtype, self.fullname, self.object, - self.options, docstringlines) + self._events.emit( + 'autodoc-process-docstring', + self.objtype, + self.fullname, + self.object, + self.options, + docstringlines, + ) - if docstringlines and docstringlines[-1] != '': + if docstringlines and docstringlines[-1]: # append a blank line to the end of the docstring docstringlines.append('') yield from docstringlines def get_sourcename(self) -> str: - if (inspect.safe_getattr(self.object, '__module__', None) and - inspect.safe_getattr(self.object, '__qualname__', None)): + obj_module = inspect.safe_getattr(self.object, '__module__', None) + obj_qualname = inspect.safe_getattr(self.object, '__qualname__', None) + if obj_module and obj_qualname: # Get the correct location of docstring from self.object # to support inherited methods fullname = f'{self.object.__module__}.{self.object.__qualname__}' @@ -723,8 +794,9 @@ def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]: msg = 'must be implemented in subclasses' raise NotImplementedError(msg) - def filter_members(self, members: list[ObjectMember], want_all: bool, - ) -> list[tuple[str, Any, bool]]: + def filter_members( + self, members: list[ObjectMember], want_all: bool + ) -> list[tuple[str, Any, bool]]: """Filter the given member list. Members are skipped if @@ -738,12 +810,22 @@ def filter_members(self, members: list[ObjectMember], want_all: bool, The user can override the skipping decision by connecting to the ``autodoc-skip-member`` event. """ + def is_filtered_inherited_member(name: str, obj: Any) -> bool: inherited_members = self.options.inherited_members or set() + seen = set() if inspect.isclass(self.object): for cls in self.object.__mro__: - if cls.__name__ in inherited_members and cls != self.object: + if name in cls.__dict__: + seen.add(cls) + if ( + cls.__name__ in inherited_members + and cls != self.object + and any( + issubclass(potential_child, cls) for potential_child in seen + ) + ): # given member is a member of specified *super class* return True if name in cls.__dict__: @@ -782,8 +864,13 @@ def is_filtered_inherited_member(name: str, obj: Any) -> bool: isattr = member is INSTANCEATTR or (namespace, membername) in attr_docs try: - doc = getdoc(member, self.get_attr, self.config.autodoc_inherit_docstrings, - self.object, membername) + doc = getdoc( + member, + self.get_attr, + self.config.autodoc_inherit_docstrings, + self.object, + membername, + ) if not isinstance(doc, str): # Ignore non-string __doc__ doc = None @@ -816,14 +903,18 @@ def is_filtered_inherited_member(name: str, obj: Any) -> bool: if ismock(member) and (namespace, membername) not in attr_docs: # mocked module or object pass - elif (self.options.exclude_members and - membername in self.options.exclude_members): + elif ( + self.options.exclude_members + and membername in self.options.exclude_members + ): # remove members given by exclude-members keep = False elif want_all and special_member_re.match(membername): # special __methods__ - if (self.options.special_members and - membername in self.options.special_members): + if ( + self.options.special_members + and membername in self.options.special_members + ): if membername == '__doc__': # NoQA: SIM114 keep = False elif is_filtered_inherited_member(membername, obj): @@ -852,8 +943,9 @@ def is_filtered_inherited_member(name: str, obj: Any) -> bool: else: keep = False else: - if (self.options.members is ALL and - is_filtered_inherited_member(membername, obj)): + if self.options.members is ALL and is_filtered_inherited_member( + membername, obj + ): keep = False else: # ignore undocumented members if :undoc-members: is not given @@ -865,17 +957,30 @@ def is_filtered_inherited_member(name: str, obj: Any) -> bool: # give the user a chance to decide whether this member # should be skipped - if self.env.app: + if self._events is not None: # let extensions preprocess docstrings - skip_user = self.env.app.emit_firstresult( - 'autodoc-skip-member', self.objtype, membername, member, - not keep, self.options) + skip_user = self._events.emit_firstresult( + 'autodoc-skip-member', + self.objtype, + membername, + member, + not keep, + self.options, + ) if skip_user is not None: keep = not skip_user except Exception as exc: - logger.warning(__('autodoc: failed to determine %s.%s (%r) to be documented, ' - 'the following exception was raised:\n%s'), - self.name, membername, member, exc, type='autodoc') + logger.warning( + __( + 'autodoc: failed to determine %s.%s (%r) to be documented, ' + 'the following exception was raised:\n%s' + ), + self.name, + membername, + member, + exc, + type='autodoc', + ) keep = False if keep: @@ -890,21 +995,24 @@ def document_members(self, all_members: bool = False) -> None: *self.options.members*. """ # set current namespace for finding members - self.env.temp_data['autodoc:module'] = self.modname + self._current_document.autodoc_module = self.modname if self.objpath: - self.env.temp_data['autodoc:class'] = self.objpath[0] + self._current_document.autodoc_class = self.objpath[0] - want_all = (all_members or - self.options.inherited_members or - self.options.members is ALL) + want_all = ( + all_members or self.options.inherited_members or self.options.members is ALL + ) # find out which members are documentable members_check_module, members = self.get_object_members(want_all) # document non-skipped members - memberdocumenters: list[tuple[Documenter, bool]] = [] - for (mname, member, isattr) in self.filter_members(members, want_all): - classes = [cls for cls in self.documenters.values() - if cls.can_document_member(member, mname, isattr, self)] + member_documenters: list[tuple[Documenter, bool]] = [] + for mname, member, isattr in self.filter_members(members, want_all): + classes = [ + cls + for cls in self.documenters.values() + if cls.can_document_member(member, mname, isattr, self) + ] if not classes: # don't know how to document this member continue @@ -914,22 +1022,39 @@ def document_members(self, all_members: bool = False) -> None: # of inner classes can be documented full_mname = f'{self.modname}::' + '.'.join((*self.objpath, mname)) documenter = classes[-1](self.directive, full_mname, self.indent) - memberdocumenters.append((documenter, isattr)) + member_documenters.append((documenter, isattr)) member_order = self.options.member_order or self.config.autodoc_member_order - memberdocumenters = self.sort_members(memberdocumenters, member_order) - - for documenter, isattr in memberdocumenters: - documenter.generate( - all_members=True, real_modname=self.real_modname, - check_module=members_check_module and not isattr) + # We now try to import all objects before ordering them. This is to + # avoid possible circular imports if we were to import objects after + # their associated documenters have been sorted. + member_documenters = [ + (documenter, isattr) + for documenter, isattr in member_documenters + if documenter.parse_name() and documenter.import_object() + ] + member_documenters = self.sort_members(member_documenters, member_order) + + for documenter, isattr in member_documenters: + assert documenter.modname + # We can directly call ._generate() since the documenters + # already called parse_name() and import_object() before. + # + # Note that those two methods above do not emit events, so + # whatever objects we deduced should not have changed. + documenter._generate( + all_members=True, + real_modname=self.real_modname, + check_module=members_check_module and not isattr, + ) # reset current objects - self.env.temp_data['autodoc:module'] = None - self.env.temp_data['autodoc:class'] = None + self._current_document.autodoc_module = '' + self._current_document.autodoc_class = '' - def sort_members(self, documenters: list[tuple[Documenter, bool]], - order: str) -> list[tuple[Documenter, bool]]: + def sort_members( + self, documenters: list[tuple[Documenter, bool]], order: str + ) -> list[tuple[Documenter, bool]]: """Sort the given member list.""" if order == 'groupwise': # sort by group; alphabetically within groups @@ -944,6 +1069,7 @@ def sort_members(self, documenters: list[tuple[Documenter, bool]], def keyfunc(entry: tuple[Documenter, bool]) -> int: fullname = entry[0].name.split('::')[1] return tagorder.get(fullname, len(tagorder)) + documenters.sort(key=keyfunc) else: # alphabetical documenters.sort(key=lambda e: e[0].name) @@ -968,16 +1094,29 @@ def generate( if not self.parse_name(): # need a module to import logger.warning( - __("don't know which module to import for autodocumenting " - '%r (try placing a "module" or "currentmodule" directive ' - 'in the document, or giving an explicit module name)'), - self.name, type='autodoc') + __( + "don't know which module to import for autodocumenting " + '%r (try placing a "module" or "currentmodule" directive ' + 'in the document, or giving an explicit module name)' + ), + self.name, + type='autodoc', + ) return # now, import the module and get object to document if not self.import_object(): return + self._generate(more_content, real_modname, check_module, all_members) + + def _generate( + self, + more_content: StringList | None = None, + real_modname: str | None = None, + check_module: bool = False, + all_members: bool = False, + ) -> None: # If there is no real module defined, figure out which to use. # The real module is used in the module analyzer to look up the module # where the attribute documentation would actually be found in. @@ -1010,10 +1149,16 @@ def generate( except PycodeError: pass - docstrings: list[str] = functools.reduce(operator.iadd, self.get_doc() or [], []) + docstrings: list[str] = functools.reduce( + operator.iadd, self.get_doc() or [], [] + ) if ismock(self.object) and not docstrings: - logger.warning(__('A mocked object is detected: %r'), - self.name, type='autodoc') + logger.warning( + __('A mocked object is detected: %r'), + self.name, + type='autodoc', + subtype='mocked_object', + ) # check __module__ of object (for members not given explicitly) if check_module: @@ -1031,8 +1176,12 @@ def generate( try: sig = self.format_signature() except Exception as exc: - logger.warning(__('error while formatting signature for %s: %s'), - self.fullname, exc, type='autodoc') + logger.warning( + __('error while formatting signature for %s: %s'), + self.fullname, + exc, + type='autodoc', + ) return # generate the directive header and options, if applicable @@ -1050,22 +1199,28 @@ def generate( class ModuleDocumenter(Documenter): - """ - Specialized Documenter subclass for modules. - """ + """Specialized Documenter subclass for modules.""" objtype = 'module' content_indent = '' _extra_indent = ' ' option_spec: ClassVar[OptionSpec] = { - 'members': members_option, 'undoc-members': bool_option, - 'no-index': bool_option, 'inherited-members': inherited_members_option, - 'show-inheritance': bool_option, 'synopsis': identity, - 'platform': identity, 'deprecated': bool_option, - 'member-order': member_order_option, 'exclude-members': exclude_members_option, - 'private-members': members_option, 'special-members': members_option, - 'imported-members': bool_option, 'ignore-module-all': bool_option, + 'members': members_option, + 'undoc-members': bool_option, + 'no-index': bool_option, + 'no-index-entry': bool_option, + 'inherited-members': inherited_members_option, + 'show-inheritance': bool_option, + 'synopsis': identity, + 'platform': identity, + 'deprecated': bool_option, + 'member-order': member_order_option, + 'exclude-members': exclude_members_option, + 'private-members': members_option, + 'special-members': members_option, + 'imported-members': bool_option, + 'ignore-module-all': bool_option, 'no-value': bool_option, 'noindex': bool_option, } @@ -1086,24 +1241,28 @@ def add_content(self, more_content: StringList | None) -> None: @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: # don't document submodules automatically return False - def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, - ) -> tuple[str | None, list[str]]: + def resolve_name( + self, modname: str | None, parents: Any, path: str, base: str + ) -> tuple[str | None, list[str]]: if modname is not None: - logger.warning(__('"::" in automodule name doesn\'t make sense'), - type='autodoc') + logger.warning( + __('"::" in automodule name doesn\'t make sense'), type='autodoc' + ) return (path or '') + base, [] def parse_name(self) -> bool: ret = super().parse_name() if self.args or self.retann: - logger.warning(__('signature arguments or return annotation ' - 'given for automodule %s'), self.fullname, - type='autodoc') + logger.warning( + __('signature arguments or return annotation given for automodule %s'), + self.fullname, + type='autodoc', + ) return ret def import_object(self, raiseerror: bool = False) -> bool: @@ -1114,9 +1273,15 @@ def import_object(self, raiseerror: bool = False) -> bool: self.__all__ = inspect.getall(self.object) except ValueError as exc: # invalid __all__ found. - logger.warning(__('__all__ should be a list of strings, not %r ' - '(in module %s) -- ignoring __all__'), - exc.args[0], self.fullname, type='autodoc') + logger.warning( + __( + '__all__ should be a list of strings, not %r ' + '(in module %s) -- ignoring __all__' + ), + exc.args[0], + self.fullname, + type='autodoc', + ) return ret @@ -1132,6 +1297,8 @@ def add_directive_header(self, sig: str) -> None: self.add_line(' :platform: ' + self.options.platform, sourcename) if self.options.deprecated: self.add_line(' :deprecated:', sourcename) + if self.options.no_index_entry: + self.add_line(' :no-index-entry:', sourcename) def get_module_members(self) -> dict[str, ObjectMember]: """Get members of target module.""" @@ -1147,7 +1314,9 @@ def get_module_members(self) -> dict[str, ObjectMember]: if ismock(value): value = undecorate(value) docstring = attr_docs.get(('', name), []) - members[name] = ObjectMember(name, value, docstring="\n".join(docstring)) + members[name] = ObjectMember( + name, value, docstring='\n'.join(docstring) + ) except AttributeError: continue @@ -1155,8 +1324,9 @@ def get_module_members(self) -> dict[str, ObjectMember]: for name in inspect.getannotations(self.object): if name not in members: docstring = attr_docs.get(('', name), []) - members[name] = ObjectMember(name, INSTANCEATTR, - docstring="\n".join(docstring)) + members[name] = ObjectMember( + name, INSTANCEATTR, docstring='\n'.join(docstring) + ) return members @@ -1180,15 +1350,20 @@ def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]: if name in members: ret.append(members[name]) else: - logger.warning(__('missing attribute mentioned in :members: option: ' - 'module %s, attribute %s'), - safe_getattr(self.object, '__name__', '???'), - name, - type='autodoc') + logger.warning( + __( + 'missing attribute mentioned in :members: option: ' + 'module %s, attribute %s' + ), + safe_getattr(self.object, '__name__', '???'), + name, + type='autodoc', + ) return False, ret - def sort_members(self, documenters: list[tuple[Documenter, bool]], - order: str) -> list[tuple[Documenter, bool]]: + def sort_members( + self, documenters: list[tuple[Documenter, bool]], order: str + ) -> list[tuple[Documenter, bool]]: if order == 'bysource' and self.__all__: assert self.__all__ is not None module_all = self.__all__ @@ -1205,6 +1380,7 @@ def keyfunc(entry: tuple[Documenter, bool]) -> int: return module_all.index(name) else: return module_all_len + documenters.sort(key=keyfunc) return documenters @@ -1213,13 +1389,13 @@ def keyfunc(entry: tuple[Documenter, bool]) -> int: class ModuleLevelDocumenter(Documenter): - """ - Specialized Documenter subclass for objects on module level (functions, + """Specialized Documenter subclass for objects on module level (functions, classes, data/constants). """ - def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, - ) -> tuple[str | None, list[str]]: + def resolve_name( + self, modname: str | None, parents: Any, path: str, base: str + ) -> tuple[str | None, list[str]]: if modname is not None: return modname, [*parents, base] if path: @@ -1228,7 +1404,7 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, # if documenting a toplevel object without explicit module, # it can be contained in another auto directive ... - modname = self.env.temp_data.get('autodoc:module') + modname = self._current_document.autodoc_module # ... or in the scope of a module directive if not modname: modname = self.env.ref_context.get('py:module') @@ -1237,13 +1413,13 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, class ClassLevelDocumenter(Documenter): - """ - Specialized Documenter subclass for objects on class level (methods, + """Specialized Documenter subclass for objects on class level (methods, attributes). """ - def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, - ) -> tuple[str | None, list[str]]: + def resolve_name( + self, modname: str | None, parents: Any, path: str, base: str + ) -> tuple[str | None, list[str]]: if modname is not None: return modname, [*parents, base] @@ -1253,19 +1429,18 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, # if documenting a class-level object without path, # there must be a current class, either from a parent # auto directive ... - mod_cls_ = self.env.temp_data.get('autodoc:class') + mod_cls = self._current_document.autodoc_class # ... or from a class directive - if mod_cls_ is None: - mod_cls_ = self.env.ref_context.get('py:class') - # ... if still None, there's no way to know - if mod_cls_ is None: + if not mod_cls: + mod_cls = self.env.ref_context.get('py:class', '') + # ... if still falsy, there's no way to know + if not mod_cls: return None, [] - mod_cls = mod_cls_ modname, sep, cls = mod_cls.rpartition('.') parents = [cls] # if the module name is still missing, get it like above if not modname: - modname = self.env.temp_data.get('autodoc:module') + modname = self._current_document.autodoc_module if not modname: modname = self.env.ref_context.get('py:module') # ... else, it stays None, which means invalid @@ -1273,8 +1448,7 @@ def resolve_name(self, modname: str | None, parents: Any, path: str, base: str, class DocstringSignatureMixin: - """ - Mixin for FunctionDocumenter and MethodDocumenter to provide the + """Mixin for FunctionDocumenter and MethodDocumenter to provide the feature of reading the signature from the docstring. """ @@ -1317,15 +1491,16 @@ def _find_signature(self) -> tuple[str | None, str | None] | None: # re-prepare docstring to ignore more leading indentation directive = self.directive # type: ignore[attr-defined] tab_width = directive.state.document.settings.tab_width - self._new_docstrings[i] = prepare_docstring('\n'.join(doclines[j + 1:]), - tab_width) + self._new_docstrings[i] = prepare_docstring( + '\n'.join(doclines[j + 1 :]), tab_width + ) if result is None: # first signature result = args, retann else: # subsequent signatures - self._signatures.append(f"({args}) -> {retann}") + self._signatures.append(f'({args}) -> {retann}') if result is not None: # finish the loop when signature found @@ -1340,8 +1515,7 @@ def get_doc(self) -> list[list[str]] | None: def format_signature(self, **kwargs: Any) -> str: self.args: str | None - if (self.args is None - and self.config.autodoc_docstring_signature): # type: ignore[attr-defined] + if self.args is None and self.config.autodoc_docstring_signature: # type: ignore[attr-defined] # only act if a signature is not explicitly given already, and if # the feature is enabled result = self._find_signature() @@ -1349,22 +1523,18 @@ def format_signature(self, **kwargs: Any) -> str: self.args, self.retann = result sig = super().format_signature(**kwargs) # type: ignore[misc] if self._signatures: - return "\n".join((sig, *self._signatures)) + return '\n'.join((sig, *self._signatures)) else: return sig class DocstringStripSignatureMixin(DocstringSignatureMixin): - """ - Mixin for AttributeDocumenter to provide the + """Mixin for AttributeDocumenter to provide the feature of stripping any function signature from the docstring. """ def format_signature(self, **kwargs: Any) -> str: - if ( - self.args is None - and self.config.autodoc_docstring_signature # type: ignore[attr-defined] - ): + if self.args is None and self.config.autodoc_docstring_signature: # type: ignore[attr-defined] # only act if a signature is not explicitly given already, and if # the feature is enabled result = self._find_signature() @@ -1377,16 +1547,14 @@ def format_signature(self, **kwargs: Any) -> str: class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore[misc] - """ - Specialized Documenter subclass for functions. - """ + """Specialized Documenter subclass for functions.""" objtype = 'function' member_order = 30 @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: # -------------------------------------------------------------------- # supports functions, builtins but, unlike Sphinx' autodoc, @@ -1405,13 +1573,15 @@ def can_document_member( # -------------------------------------------------------------------- def format_args(self, **kwargs: Any) -> str: - if self.config.autodoc_typehints in ('none', 'description'): + if self.config.autodoc_typehints in {'none', 'description'}: kwargs.setdefault('show_annotation', False) - if self.config.autodoc_typehints_format == "short": + if self.config.autodoc_typehints_format == 'short': kwargs.setdefault('unqualified_typehints', True) + if self.config.python_display_short_literal_types: + kwargs.setdefault('short_literals', True) try: - self.env.app.emit('autodoc-before-process-signature', self.object, False) + self._events.emit('autodoc-before-process-signature', self.object, False) # ---------------------------------------------------------------- # Issue #9976: Support the _sage_argspec_ attribute which makes it # possible to get argument specification of decorated callables in @@ -1438,8 +1608,9 @@ def format_args(self, **kwargs: Any) -> str: args = sage_formatargspec(*argspec) # ---------------------------------------------------------------- except TypeError as exc: - logger.warning(__("Failed to get a function signature for %s: %s"), - self.fullname, exc) + logger.warning( + __('Failed to get a function signature for %s: %s'), self.fullname, exc + ) return '' except ValueError: args = '' @@ -1456,17 +1627,23 @@ def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() super().add_directive_header(sig) - if inspect.iscoroutinefunction(self.object) or inspect.isasyncgenfunction(self.object): + is_coro = inspect.iscoroutinefunction(self.object) + is_acoro = inspect.isasyncgenfunction(self.object) + if is_coro or is_acoro: self.add_line(' :async:', sourcename) def format_signature(self, **kwargs: Any) -> str: - if self.config.autodoc_typehints_format == "short": + if self.config.autodoc_typehints_format == 'short': kwargs.setdefault('unqualified_typehints', True) + if self.config.python_display_short_literal_types: + kwargs.setdefault('short_literals', True) sigs = [] - if (self.analyzer and - '.'.join(self.objpath) in self.analyzer.overloads and - self.config.autodoc_typehints != 'none'): + if ( + self.analyzer + and '.'.join(self.objpath) in self.analyzer.overloads + and self.config.autodoc_typehints != 'none' + ): # Use signatures for overloaded functions instead of the implementation function. overloaded = True else: @@ -1487,18 +1664,20 @@ def format_signature(self, **kwargs: Any) -> str: documenter.objpath = [''] sigs.append(documenter.format_signature()) if overloaded and self.analyzer is not None: - actual = inspect.signature(self.object, - type_aliases=self.config.autodoc_type_aliases) + actual = inspect.signature( + self.object, type_aliases=self.config.autodoc_type_aliases + ) __globals__ = safe_getattr(self.object, '__globals__', {}) for overload in self.analyzer.overloads['.'.join(self.objpath)]: overload = self.merge_default_value(actual, overload) - overload = evaluate_signature(overload, __globals__, - self.config.autodoc_type_aliases) + overload = evaluate_signature( + overload, __globals__, self.config.autodoc_type_aliases + ) sig = stringify_signature(overload, **kwargs) sigs.append(sig) - return "\n".join(sigs) + return '\n'.join(sigs) def merge_default_value(self, actual: Signature, overload: Signature) -> Signature: """Merge default values of actual implementation to the overload variants.""" @@ -1510,13 +1689,16 @@ def merge_default_value(self, actual: Signature, overload: Signature) -> Signatu return overload.replace(parameters=parameters) - def annotate_to_first_argument(self, func: Callable, typ: type) -> Callable | None: + def annotate_to_first_argument( + self, func: Callable[..., Any], typ: type + ) -> Callable[..., Any] | None: """Annotate type hint to the first argument of function if needed.""" try: sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases) except TypeError as exc: - logger.warning(__("Failed to get a function signature for %s: %s"), - self.fullname, exc) + logger.warning( + __('Failed to get a function signature for %s: %s'), self.fullname, exc + ) return None except ValueError: return None @@ -1531,8 +1713,7 @@ def dummy(): # type: ignore[no-untyped-def] # NoQA: ANN202 if params[0].annotation is Parameter.empty: params[0] = params[0].replace(annotation=typ) try: - dummy.__signature__ = sig.replace( # type: ignore[attr-defined] - parameters=params) + dummy.__signature__ = sig.replace(parameters=params) # type: ignore[attr-defined] return dummy except (AttributeError, TypeError): # failed to update signature (ex. built-in or extension types) @@ -1542,9 +1723,7 @@ def dummy(): # type: ignore[no-untyped-def] # NoQA: ANN202 class DecoratorDocumenter(FunctionDocumenter): - """ - Specialized Documenter subclass for decorator functions. - """ + """Specialized Documenter subclass for decorator functions.""" objtype = 'decorator' @@ -1562,30 +1741,33 @@ def format_args(self, **kwargs: Any) -> str: # Types which have confusing metaclass signatures it would be best not to show. # These are listed by name, rather than storing the objects themselves, to avoid # needing to import the modules. -_METACLASS_CALL_BLACKLIST = [ - 'enum.EnumMeta.__call__', -] +_METACLASS_CALL_BLACKLIST = frozenset({ + 'enum.EnumType.__call__', +}) # Types whose __new__ signature is a pass-through. -_CLASS_NEW_BLACKLIST = [ +_CLASS_NEW_BLACKLIST = frozenset({ 'typing.Generic.__new__', -] +}) class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type: ignore[misc] - """ - Specialized Documenter subclass for classes. - """ + """Specialized Documenter subclass for classes.""" objtype = 'class' member_order = 20 option_spec: ClassVar[OptionSpec] = { - 'members': members_option, 'undoc-members': bool_option, - 'no-index': bool_option, 'inherited-members': inherited_members_option, - 'show-inheritance': bool_option, 'member-order': member_order_option, + 'members': members_option, + 'undoc-members': bool_option, + 'no-index': bool_option, + 'no-index-entry': bool_option, + 'inherited-members': inherited_members_option, + 'show-inheritance': bool_option, + 'member-order': member_order_option, 'exclude-members': exclude_members_option, - 'private-members': members_option, 'special-members': members_option, + 'private-members': members_option, + 'special-members': members_option, 'class-doc-from': class_doc_from_option, 'noindex': bool_option, } @@ -1615,10 +1797,11 @@ def __init__(self, *args: Any) -> None: @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: return isinstance(member, type) or ( - isattr and isinstance(member, NewType | TypeVar)) + isattr and isinstance(member, NewType | TypeVar) + ) def import_object(self, raiseerror: bool = False) -> bool: ret = super().import_object(raiseerror) @@ -1626,7 +1809,7 @@ def import_object(self, raiseerror: bool = False) -> bool: # as data/attribute if ret: if hasattr(self.object, '__name__'): - self.doc_as_attr = (self.objpath[-1] != self.object.__name__) + self.doc_as_attr = self.objpath[-1] != self.object.__name__ # ------------------------------------------------------------------- # Issue #27692, #7448: The original goal of this was that if some # class is aliased, the alias is generated as a link rather than @@ -1694,7 +1877,7 @@ def import_object(self, raiseerror: bool = False) -> bool: if isinstance(self.object, NewType | TypeVar): modname = getattr(self.object, '__module__', self.modname) if modname != self.modname and self.modname.startswith(modname): - bases = self.modname[len(modname):].strip('.').split('.') + bases = self.modname[len(modname) :].strip('.').split('.') self.objpath = bases + self.objpath self.modname = modname return ret @@ -1716,24 +1899,32 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: # This sequence is copied from inspect._signature_from_callable. # ValueError means that no signature could be found, so we keep going. - # First, we check the obj has a __signature__ attribute - if (hasattr(self.object, '__signature__') and - isinstance(self.object.__signature__, Signature)): - return None, None, self.object.__signature__ + # First, we check if obj has a __signature__ attribute + if hasattr(self.object, '__signature__'): + object_sig = self.object.__signature__ + if isinstance(object_sig, Signature): + return None, None, object_sig + if sys.version_info[:2] in {(3, 12), (3, 13)} and callable(object_sig): + # Support for enum.Enum.__signature__ in Python 3.12 + if isinstance(object_sig_str := object_sig(), str): + return None, None, inspect.signature_from_str(object_sig_str) # Next, let's see if it has an overloaded __call__ defined # in its metaclass call = get_user_defined_function_or_method(type(self.object), '__call__') if call is not None: - if f"{call.__module__}.{call.__qualname__}" in _METACLASS_CALL_BLACKLIST: + if f'{call.__module__}.{call.__qualname__}' in _METACLASS_CALL_BLACKLIST: call = None if call is not None: - self.env.app.emit('autodoc-before-process-signature', call, True) + self._events.emit('autodoc-before-process-signature', call, True) try: - sig = inspect.signature(call, bound_method=True, - type_aliases=self.config.autodoc_type_aliases) + sig = inspect.signature( + call, + bound_method=True, + type_aliases=self.config.autodoc_type_aliases, + ) return type(self.object), '__call__', sig except ValueError: pass @@ -1742,14 +1933,17 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: new = get_user_defined_function_or_method(self.object, '__new__') if new is not None: - if f"{new.__module__}.{new.__qualname__}" in _CLASS_NEW_BLACKLIST: + if f'{new.__module__}.{new.__qualname__}' in _CLASS_NEW_BLACKLIST: new = None if new is not None: - self.env.app.emit('autodoc-before-process-signature', new, True) + self._events.emit('autodoc-before-process-signature', new, True) try: - sig = inspect.signature(new, bound_method=True, - type_aliases=self.config.autodoc_type_aliases) + sig = inspect.signature( + new, + bound_method=True, + type_aliases=self.config.autodoc_type_aliases, + ) return self.object, '__new__', sig except ValueError: pass @@ -1757,10 +1951,13 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: # Finally, we should have at least __init__ implemented init = get_user_defined_function_or_method(self.object, '__init__') if init is not None: - self.env.app.emit('autodoc-before-process-signature', init, True) + self._events.emit('autodoc-before-process-signature', init, True) try: - sig = inspect.signature(init, bound_method=True, - type_aliases=self.config.autodoc_type_aliases) + sig = inspect.signature( + init, + bound_method=True, + type_aliases=self.config.autodoc_type_aliases, + ) return self.object, '__init__', sig except ValueError: pass @@ -1769,10 +1966,13 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: # handle it. # We don't know the exact method that inspect.signature will read # the signature from, so just pass the object itself to our hook. - self.env.app.emit('autodoc-before-process-signature', self.object, False) + self._events.emit('autodoc-before-process-signature', self.object, False) try: - sig = inspect.signature(self.object, bound_method=False, - type_aliases=self.config.autodoc_type_aliases) + sig = inspect.signature( + self.object, + bound_method=False, + type_aliases=self.config.autodoc_type_aliases, + ) return None, None, sig except ValueError: pass @@ -1782,17 +1982,22 @@ def get_user_defined_function_or_method(obj: Any, attr: str) -> Any: return None, None, None def format_args(self, **kwargs: Any) -> str: - if self.config.autodoc_typehints in ('none', 'description'): + if self.config.autodoc_typehints in {'none', 'description'}: kwargs.setdefault('show_annotation', False) - if self.config.autodoc_typehints_format == "short": + if self.config.autodoc_typehints_format == 'short': kwargs.setdefault('unqualified_typehints', True) + if self.config.python_display_short_literal_types: + kwargs.setdefault('short_literals', True) try: self._signature_class, _signature_method_name, sig = self._get_signature() except TypeError as exc: # __signature__ attribute contained junk - logger.warning(__("Failed to get a constructor signature for %s: %s"), - self.fullname, exc) + logger.warning( + __('Failed to get a constructor signature for %s: %s'), + self.fullname, + exc, + ) return '' self._signature_method_name = _signature_method_name or '' @@ -1822,8 +2027,10 @@ def format_signature(self, **kwargs: Any) -> str: # do not show signatures return '' - if self.config.autodoc_typehints_format == "short": + if self.config.autodoc_typehints_format == 'short': kwargs.setdefault('unqualified_typehints', True) + if self.config.python_display_short_literal_types: + kwargs.setdefault('short_literals', True) sig = super().format_signature() sigs = [] @@ -1831,21 +2038,25 @@ def format_signature(self, **kwargs: Any) -> str: overloads = self.get_overloaded_signatures() if overloads and self.config.autodoc_typehints != 'none': # Use signatures for overloaded methods instead of the implementation method. - method = safe_getattr(self._signature_class, self._signature_method_name, None) + method = safe_getattr( + self._signature_class, self._signature_method_name, None + ) __globals__ = safe_getattr(method, '__globals__', {}) for overload in overloads: - overload = evaluate_signature(overload, __globals__, - self.config.autodoc_type_aliases) + overload = evaluate_signature( + overload, __globals__, self.config.autodoc_type_aliases + ) parameters = list(overload.parameters.values()) - overload = overload.replace(parameters=parameters[1:], - return_annotation=Parameter.empty) + overload = overload.replace( + parameters=parameters[1:], return_annotation=Parameter.empty + ) sig = stringify_signature(overload, **kwargs) sigs.append(sig) else: sigs.append(sig) - return "\n".join(sigs) + return '\n'.join(sigs) def get_overloaded_signatures(self) -> list[Signature]: if self._signature_class and self._signature_method_name: @@ -1892,8 +2103,12 @@ def add_directive_header(self, sig: str) -> None: self.add_line(' :final:', sourcename) canonical_fullname = self.get_canonical_fullname() - if (not self.doc_as_attr and not isinstance(self.object, NewType) - and canonical_fullname and self.fullname != canonical_fullname): + if ( + not self.doc_as_attr + and not isinstance(self.object, NewType) + and canonical_fullname + and self.fullname != canonical_fullname + ): self.add_line(' :canonical: %s' % canonical_fullname, sourcename) # add inheritance info, if wanted @@ -1908,21 +2123,24 @@ def add_directive_header(self, sig: str) -> None: else: bases = [] - self.env.events.emit('autodoc-process-bases', - self.fullname, self.object, self.options, bases) + self._events.emit( + 'autodoc-process-bases', self.fullname, self.object, self.options, bases + ) - if self.config.autodoc_typehints_format == "short": - base_classes = [restify(cls, "smart") for cls in bases] - else: - base_classes = [restify(cls) for cls in bases] + mode = _get_render_mode(self.config.autodoc_typehints_format) + base_classes = [restify(cls, mode=mode) for cls in bases] sourcename = self.get_sourcename() self.add_line('', sourcename) self.add_line(' ' + _('Bases: %s') % ', '.join(base_classes), sourcename) def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]: - members = get_class_members(self.object, self.objpath, self.get_attr, - self.config.autodoc_inherit_docstrings) + members = get_class_members( + self.object, + self.objpath, + self.get_attr, + self.config.autodoc_inherit_docstrings, + ) if not want_all: if not self.options.members: return False, [] @@ -1932,8 +2150,12 @@ def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]: if name in members: selected.append(members[name]) else: - logger.warning(__('missing attribute %s in object %s'), - name, self.fullname, type='autodoc') + logger.warning( + __('missing attribute %s in object %s'), + name, + self.fullname, + type='autodoc', + ) return False, selected elif self.options.inherited_members: return False, list(members.values()) @@ -1955,7 +2177,9 @@ def get_doc(self) -> list[list[str]] | None: if lines is not None: return lines - classdoc_from = self.options.get('class-doc-from', self.config.autoclass_content) + classdoc_from = self.options.get( + 'class-doc-from', self.config.autoclass_content + ) docstrings = [] attrdocstring = getdoc(self.object, self.get_attr) @@ -1964,26 +2188,36 @@ def get_doc(self) -> list[list[str]] | None: # for classes, what the "docstring" is can be controlled via a # config value; the default is only the class docstring - if classdoc_from in ('both', 'init'): + if classdoc_from in {'both', 'init'}: __init__ = self.get_attr(self.object, '__init__', None) - initdocstring = getdoc(__init__, self.get_attr, - self.config.autodoc_inherit_docstrings, - self.object, '__init__') + initdocstring = getdoc( + __init__, + self.get_attr, + self.config.autodoc_inherit_docstrings, + self.object, + '__init__', + ) # for new-style classes, no __init__ means default __init__ - if (initdocstring is not None and - (initdocstring == object.__init__.__doc__ or # for pypy - initdocstring.strip() == object.__init__.__doc__)): # for !pypy + if initdocstring is not None and ( + initdocstring == object.__init__.__doc__ # for pypy + or initdocstring.strip() == object.__init__.__doc__ # for !pypy + ): initdocstring = None if not initdocstring: # try __new__ __new__ = self.get_attr(self.object, '__new__', None) - initdocstring = getdoc(__new__, self.get_attr, - self.config.autodoc_inherit_docstrings, - self.object, '__new__') + initdocstring = getdoc( + __new__, + self.get_attr, + self.config.autodoc_inherit_docstrings, + self.object, + '__new__', + ) # for new-style classes, no __new__ means default __new__ - if (initdocstring is not None and - (initdocstring == object.__new__.__doc__ or # for pypy - initdocstring.strip() == object.__new__.__doc__)): # for !pypy + if initdocstring is not None and ( + initdocstring == object.__new__.__doc__ # for pypy + or initdocstring.strip() == object.__new__.__doc__ # for !pypy + ): initdocstring = None if initdocstring: if classdoc_from == 'init': @@ -2007,34 +2241,29 @@ def get_variable_comment(self) -> list[str] | None: return None def add_content(self, more_content: StringList | None) -> None: + mode = _get_render_mode(self.config.autodoc_typehints_format) + short_literals = self.config.python_display_short_literal_types + if isinstance(self.object, NewType): - if self.config.autodoc_typehints_format == "short": - supertype = restify(self.object.__supertype__, "smart") - else: - supertype = restify(self.object.__supertype__) + supertype = restify(self.object.__supertype__, mode=mode) more_content = StringList([_('alias of %s') % supertype, ''], source='') if isinstance(self.object, TypeVar): attrs = [repr(self.object.__name__)] - for constraint in self.object.__constraints__: - if self.config.autodoc_typehints_format == "short": - attrs.append(stringify_annotation(constraint, "smart")) - else: - attrs.append(stringify_annotation(constraint)) + attrs.extend( + stringify_annotation(constraint, mode, short_literals=short_literals) + for constraint in self.object.__constraints__ + ) if self.object.__bound__: - if self.config.autodoc_typehints_format == "short": - bound = restify(self.object.__bound__, "smart") - else: - bound = restify(self.object.__bound__) - attrs.append(r"bound=\ " + bound) + bound = restify(self.object.__bound__, mode=mode) + attrs.append(r'bound=\ ' + bound) if self.object.__covariant__: - attrs.append("covariant=True") + attrs.append('covariant=True') if self.object.__contravariant__: - attrs.append("contravariant=True") + attrs.append('contravariant=True') more_content = StringList( - [_('alias of TypeVar(%s)') % ", ".join(attrs), ''], - source='', + [_('alias of TypeVar(%s)') % ', '.join(attrs), ''], source='' ) if self.doc_as_attr and self.modname != self.get_real_modname(): try: @@ -2046,10 +2275,7 @@ def add_content(self, more_content: StringList | None) -> None: if self.doc_as_attr and not self.get_variable_comment(): try: - if self.config.autodoc_typehints_format == "short": - alias = restify(self.object, "smart") - else: - alias = restify(self.object) + alias = restify(self.object, mode=mode) more_content = StringList([_('alias of %s') % alias], source='') except AttributeError: pass # Invalid class object is passed. @@ -2073,15 +2299,15 @@ def generate( # If a class gets imported into the module real_modname # the analyzer won't find the source of the class, if # it looks in real_modname. - return super().generate(more_content=more_content, - check_module=check_module, - all_members=all_members) + return super().generate( + more_content=more_content, + check_module=check_module, + all_members=all_members, + ) class ExceptionDocumenter(ClassDocumenter): - """ - Specialized ClassDocumenter subclass for exceptions. - """ + """Specialized ClassDocumenter subclass for exceptions.""" objtype = 'exception' member_order = 10 @@ -2091,7 +2317,7 @@ class ExceptionDocumenter(ClassDocumenter): @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: try: return isinstance(member, type) and issubclass(member, BaseException) @@ -2129,21 +2355,20 @@ def update_content(self, more_content: StringList) -> None: class GenericAliasMixin(DataDocumenterMixinBase): - """ - Mixin for DataDocumenter and AttributeDocumenter to provide the feature for + """Mixin for DataDocumenter and AttributeDocumenter to provide the feature for supporting GenericAliases. """ def should_suppress_directive_header(self) -> bool: - return (inspect.isgenericalias(self.object) or - super().should_suppress_directive_header()) + return ( + inspect.isgenericalias(self.object) + or super().should_suppress_directive_header() + ) def update_content(self, more_content: StringList) -> None: if inspect.isgenericalias(self.object): - if self.config.autodoc_typehints_format == "short": - alias = restify(self.object, "smart") - else: - alias = restify(self.object) + mode = _get_render_mode(self.config.autodoc_typehints_format) + alias = restify(self.object, mode=mode) more_content.append(_('alias of %s') % alias, '') more_content.append('', '') @@ -2152,8 +2377,7 @@ def update_content(self, more_content: StringList) -> None: class UninitializedGlobalVariableMixin(DataDocumenterMixinBase): - """ - Mixin for DataDocumenter to provide the feature for supporting uninitialized + """Mixin for DataDocumenter to provide the feature for supporting uninitialized (type annotation only) global variables. """ @@ -2165,9 +2389,12 @@ def import_object(self, raiseerror: bool = False) -> bool: try: with mock(self.config.autodoc_mock_imports): parent = import_module(self.modname) - annotations = get_type_hints(parent, None, - self.config.autodoc_type_aliases, - include_extras=True) + annotations = get_type_hints( + parent, + None, + self.config.autodoc_type_aliases, + include_extras=True, + ) if self.objpath[-1] in annotations: self.object = UNINITIALIZED_ATTR self.parent = parent @@ -2182,8 +2409,9 @@ def import_object(self, raiseerror: bool = False) -> bool: return False def should_suppress_value_header(self) -> bool: - return (self.object is UNINITIALIZED_ATTR or - super().should_suppress_value_header()) + return ( + self.object is UNINITIALIZED_ATTR or super().should_suppress_value_header() + ) def get_doc(self) -> list[list[str]] | None: if self.object is UNINITIALIZED_ATTR: @@ -2192,22 +2420,21 @@ def get_doc(self) -> list[list[str]] | None: return super().get_doc() # type: ignore[misc] -class DataDocumenter(GenericAliasMixin, - UninitializedGlobalVariableMixin, ModuleLevelDocumenter): - """ - Specialized Documenter subclass for data items. - """ +class DataDocumenter( + GenericAliasMixin, UninitializedGlobalVariableMixin, ModuleLevelDocumenter +): + """Specialized Documenter subclass for data items.""" objtype = 'data' member_order = 40 priority = -10 option_spec: ClassVar[OptionSpec] = dict(ModuleLevelDocumenter.option_spec) - option_spec["annotation"] = annotation_option - option_spec["no-value"] = bool_option + option_spec['annotation'] = annotation_option + option_spec['no-value'] = bool_option @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: return isinstance(parent, ModuleDocumenter) and isattr @@ -2220,7 +2447,7 @@ def update_annotations(self, parent: Any) -> None: analyzer = ModuleAnalyzer.for_module(self.modname) analyzer.analyze() for (classname, attrname), annotation in analyzer.annotations.items(): - if classname == '' and attrname not in annotations: + if not classname and attrname not in annotations: annotations[attrname] = annotation except PycodeError: pass @@ -2238,7 +2465,8 @@ def should_suppress_value_header(self) -> bool: else: doc = self.get_doc() or [] docstring, metadata = separate_metadata( - '\n'.join(functools.reduce(operator.iadd, doc, []))) + '\n'.join(functools.reduce(operator.iadd, doc, [])) + ) if 'hide-value' in metadata: return True @@ -2247,29 +2475,38 @@ def should_suppress_value_header(self) -> bool: def add_directive_header(self, sig: str) -> None: super().add_directive_header(sig) sourcename = self.get_sourcename() - if self.options.annotation is SUPPRESS or self.should_suppress_directive_header(): + if ( + self.options.annotation is SUPPRESS + or self.should_suppress_directive_header() + ): pass elif self.options.annotation: - self.add_line(' :annotation: %s' % self.options.annotation, - sourcename) + self.add_line(' :annotation: %s' % self.options.annotation, sourcename) else: if self.config.autodoc_typehints != 'none': # obtain annotation for this data - annotations = get_type_hints(self.parent, None, - self.config.autodoc_type_aliases, - include_extras=True) + annotations = get_type_hints( + self.parent, + None, + self.config.autodoc_type_aliases, + include_extras=True, + ) if self.objpath[-1] in annotations: - if self.config.autodoc_typehints_format == "short": - objrepr = stringify_annotation(annotations.get(self.objpath[-1]), - "smart") - else: - objrepr = stringify_annotation(annotations.get(self.objpath[-1]), - "fully-qualified-except-typing") + mode = _get_render_mode(self.config.autodoc_typehints_format) + short_literals = self.config.python_display_short_literal_types + objrepr = stringify_annotation( + annotations.get(self.objpath[-1]), + mode, + short_literals=short_literals, + ) self.add_line(' :type: ' + objrepr, sourcename) try: - if (self.options.no_value or self.should_suppress_value_header() or - ismock(self.object)): + if ( + self.options.no_value + or self.should_suppress_value_header() + or ismock(self.object) + ): pass else: objrepr = object_description(self.object) @@ -2317,9 +2554,7 @@ def add_content(self, more_content: StringList | None) -> None: class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: ignore[misc] - """ - Specialized Documenter subclass for methods (normal, static and class). - """ + """Specialized Documenter subclass for methods (normal, static and class).""" objtype = 'method' directivetype = 'method' @@ -2328,7 +2563,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type: @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: return inspect.isroutine(member) and not isinstance(parent, ModuleDocumenter) @@ -2338,22 +2573,23 @@ def import_object(self, raiseerror: bool = False) -> bool: return ret # to distinguish classmethod/staticmethod - obj = self.parent.__dict__.get(self.object_name) - if obj is None: - obj = self.object - - if (inspect.isclassmethod(obj) or - inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name)): - # document class and static members before ordinary ones - self.member_order = self.member_order - 1 - + obj = self.parent.__dict__.get(self.object_name, self.object) + if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name): + # document static members before regular methods + self.member_order -= 1 + elif inspect.isclassmethod(obj): + # document class methods before static methods as + # they usually behave as alternative constructors + self.member_order -= 2 return ret def format_args(self, **kwargs: Any) -> str: - if self.config.autodoc_typehints in ('none', 'description'): + if self.config.autodoc_typehints in {'none', 'description'}: kwargs.setdefault('show_annotation', False) - if self.config.autodoc_typehints_format == "short": + if self.config.autodoc_typehints_format == 'short': kwargs.setdefault('unqualified_typehints', True) + if self.config.python_display_short_literal_types: + kwargs.setdefault('short_literals', True) # ----------------------------------------------------------------- # Issue #9976: Support the _sage_argspec_ attribute which makes it @@ -2396,8 +2632,11 @@ def add_directive_header(self, sig: str) -> None: self.add_line(' :abstractmethod:', sourcename) if inspect.iscoroutinefunction(obj) or inspect.isasyncgenfunction(obj): self.add_line(' :async:', sourcename) - if (inspect.isclassmethod(obj) or - inspect.is_singledispatch_method(obj) and inspect.isclassmethod(obj.func)): + if ( + inspect.is_classmethod_like(obj) + or inspect.is_singledispatch_method(obj) + and inspect.is_classmethod_like(obj.func) + ): self.add_line(' :classmethod:', sourcename) if inspect.isstaticmethod(obj, cls=self.parent, name=self.object_name): self.add_line(' :staticmethod:', sourcename) @@ -2423,13 +2662,16 @@ def merge_default_value(self, actual: Signature, overload: Signature) -> Signatu return overload.replace(parameters=parameters) - def annotate_to_first_argument(self, func: Callable, typ: type) -> Callable | None: + def annotate_to_first_argument( + self, func: Callable[..., Any], typ: type + ) -> Callable[..., Any] | None: """Annotate type hint to the first argument of function if needed.""" try: sig = inspect.signature(func, type_aliases=self.config.autodoc_type_aliases) except TypeError as exc: - logger.warning(__("Failed to get a method signature for %s: %s"), - self.fullname, exc) + logger.warning( + __('Failed to get a method signature for %s: %s'), self.fullname, exc + ) return None except ValueError: return None @@ -2445,7 +2687,8 @@ def dummy(): # type: ignore[no-untyped-def] # NoQA: ANN202 params[1] = params[1].replace(annotation=typ) try: dummy.__signature__ = sig.replace( # type: ignore[attr-defined] - parameters=params) + parameters=params + ) return dummy except (AttributeError, TypeError): # failed to update signature (ex. built-in or extension types) @@ -2461,12 +2704,17 @@ def get_doc(self) -> list[list[str]] | None: # `DocstringSignatureMixin`. return self._new_docstrings if self.objpath[-1] == '__init__': - docstring = getdoc(self.object, self.get_attr, - self.config.autodoc_inherit_docstrings, - self.parent, self.object_name) - if (docstring is not None and - (docstring == object.__init__.__doc__ or # for pypy - docstring.strip() == object.__init__.__doc__)): # for !pypy + docstring = getdoc( + self.object, + self.get_attr, + self.config.autodoc_inherit_docstrings, + self.parent, + self.object_name, + ) + if docstring is not None and ( + docstring == object.__init__.__doc__ # for pypy + or docstring.strip() == object.__init__.__doc__ # for !pypy + ): docstring = None if docstring: tab_width = self.directive.state.document.settings.tab_width @@ -2474,12 +2722,17 @@ def get_doc(self) -> list[list[str]] | None: else: return [] elif self.objpath[-1] == '__new__': - docstring = getdoc(self.object, self.get_attr, - self.config.autodoc_inherit_docstrings, - self.parent, self.object_name) - if (docstring is not None and - (docstring == object.__new__.__doc__ or # for pypy - docstring.strip() == object.__new__.__doc__)): # for !pypy + docstring = getdoc( + self.object, + self.get_attr, + self.config.autodoc_inherit_docstrings, + self.parent, + self.object_name, + ) + if docstring is not None and ( + docstring == object.__new__.__doc__ # for pypy + or docstring.strip() == object.__new__.__doc__ # for !pypy + ): docstring = None if docstring: tab_width = self.directive.state.document.settings.tab_width @@ -2491,8 +2744,7 @@ def get_doc(self) -> list[list[str]] | None: class NonDataDescriptorMixin(DataDocumenterMixinBase): - """ - Mixin for AttributeDocumenter to provide the feature for supporting non + """Mixin for AttributeDocumenter to provide the feature for supporting non data-descriptors. .. note:: This mix-in must be inherited after other mix-ins. Otherwise, docstring @@ -2509,8 +2761,10 @@ def import_object(self, raiseerror: bool = False) -> bool: return ret def should_suppress_value_header(self) -> bool: - return (not getattr(self, 'non_data_descriptor', False) or - super().should_suppress_directive_header()) + return ( + not getattr(self, 'non_data_descriptor', False) + or super().should_suppress_directive_header() + ) def get_doc(self) -> list[list[str]] | None: if getattr(self, 'non_data_descriptor', False): @@ -2522,9 +2776,7 @@ def get_doc(self) -> list[list[str]] | None: class SlotsMixin(DataDocumenterMixinBase): - """ - Mixin for AttributeDocumenter to provide the feature for supporting __slots__. - """ + """Mixin for AttributeDocumenter to provide the feature for supporting __slots__.""" def isslotsattribute(self) -> bool: """Check the subject is an attribute in __slots__.""" @@ -2553,25 +2805,29 @@ def get_doc(self) -> list[list[str]] | None: if self.object is SLOTSATTR: try: parent___slots__ = inspect.getslots(self.parent) - if parent___slots__ and (docstring := parent___slots__.get(self.objpath[-1])): + if parent___slots__ and ( + docstring := parent___slots__.get(self.objpath[-1]) + ): docstring = prepare_docstring(docstring) return [docstring] else: return [] except ValueError as exc: - logger.warning(__('Invalid __slots__ found on %s. Ignored.'), - (self.parent.__qualname__, exc), type='autodoc') + logger.warning( + __('Invalid __slots__ found on %s. Ignored.'), + (self.parent.__qualname__, exc), + type='autodoc', + ) return [] else: return super().get_doc() # type: ignore[misc] class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase): - """ - Mixin for AttributeDocumenter to provide the feature for supporting runtime + """Mixin for AttributeDocumenter to provide the feature for supporting runtime instance attributes (that are defined in __init__() methods with doc-comments). - Example: + Example:: class Foo: def __init__(self): @@ -2615,7 +2871,9 @@ def import_object(self, raiseerror: bool = False) -> bool: try: with mock(self.config.autodoc_mock_imports): ret = import_object( - self.modname, self.objpath[:-1], 'class', + self.modname, + self.objpath[:-1], + 'class', attrgetter=self.get_attr, # type: ignore[attr-defined] ) parent = ret[3] @@ -2633,23 +2891,26 @@ def import_object(self, raiseerror: bool = False) -> bool: return False def should_suppress_value_header(self) -> bool: - return (self.object is self.RUNTIME_INSTANCE_ATTRIBUTE or - super().should_suppress_value_header()) + return ( + self.object is self.RUNTIME_INSTANCE_ATTRIBUTE + or super().should_suppress_value_header() + ) def get_doc(self) -> list[list[str]] | None: - if (self.object is self.RUNTIME_INSTANCE_ATTRIBUTE and - self.is_runtime_instance_attribute_not_commented(self.parent)): + if ( + self.object is self.RUNTIME_INSTANCE_ATTRIBUTE + and self.is_runtime_instance_attribute_not_commented(self.parent) + ): return None else: return super().get_doc() # type: ignore[misc] class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase): - """ - Mixin for AttributeDocumenter to provide the feature for supporting uninitialized + """Mixin for AttributeDocumenter to provide the feature for supporting uninitialized instance attributes (PEP-526 styled, annotation only attributes). - Example: + Example:: class Foo: attr: int #: This is a target of this mix-in. @@ -2657,8 +2918,9 @@ class Foo: def is_uninitialized_instance_attribute(self, parent: Any) -> bool: """Check the subject is an annotation only attribute.""" - annotations = get_type_hints(parent, None, self.config.autodoc_type_aliases, - include_extras=True) + annotations = get_type_hints( + parent, None, self.config.autodoc_type_aliases, include_extras=True + ) return self.objpath[-1] in annotations def import_object(self, raiseerror: bool = False) -> bool: @@ -2670,7 +2932,9 @@ def import_object(self, raiseerror: bool = False) -> bool: except ImportError as exc: try: ret = import_object( - self.modname, self.objpath[:-1], 'class', + self.modname, + self.objpath[:-1], + 'class', attrgetter=self.get_attr, # type: ignore[attr-defined] ) parent = ret[3] @@ -2688,8 +2952,9 @@ def import_object(self, raiseerror: bool = False) -> bool: return False def should_suppress_value_header(self) -> bool: - return (self.object is UNINITIALIZED_ATTR or - super().should_suppress_value_header()) + return ( + self.object is UNINITIALIZED_ATTR or super().should_suppress_value_header() + ) def get_doc(self) -> list[list[str]] | None: if self.object is UNINITIALIZED_ATTR: @@ -2697,19 +2962,22 @@ def get_doc(self) -> list[list[str]] | None: return super().get_doc() # type: ignore[misc] -class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc] - RuntimeInstanceAttributeMixin, - UninitializedInstanceAttributeMixin, NonDataDescriptorMixin, - DocstringStripSignatureMixin, ClassLevelDocumenter): - """ - Specialized Documenter subclass for attributes. - """ +class AttributeDocumenter( # type: ignore[misc] + GenericAliasMixin, + SlotsMixin, + RuntimeInstanceAttributeMixin, + UninitializedInstanceAttributeMixin, + NonDataDescriptorMixin, + DocstringStripSignatureMixin, + ClassLevelDocumenter, +): + """Specialized Documenter subclass for attributes.""" objtype = 'attribute' member_order = 60 option_spec: ClassVar[OptionSpec] = dict(ModuleLevelDocumenter.option_spec) - option_spec["annotation"] = annotation_option - option_spec["no-value"] = bool_option + option_spec['annotation'] = annotation_option + option_spec['no-value'] = bool_option # must be higher than the MethodDocumenter, else it will recognize # some non-data descriptors as methods @@ -2717,11 +2985,13 @@ class AttributeDocumenter(GenericAliasMixin, SlotsMixin, # type: ignore[misc] @staticmethod def is_function_or_method(obj: Any) -> bool: - return inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj) + return ( + inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj) + ) @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: if isinstance(parent, ModuleDocumenter): return False @@ -2765,7 +3035,8 @@ def update_annotations(self, parent: Any) -> None: analyzer = ModuleAnalyzer.for_module(module) analyzer.analyze() - for (classname, attrname), annotation in analyzer.annotations.items(): + anns = analyzer.annotations + for (classname, attrname), annotation in anns.items(): if classname == qualname and attrname not in annotations: annotations[attrname] = annotation except (AttributeError, PycodeError): @@ -2794,7 +3065,8 @@ def should_suppress_value_header(self) -> bool: doc = self.get_doc() if doc: docstring, metadata = separate_metadata( - '\n'.join(functools.reduce(operator.iadd, doc, []))) + '\n'.join(functools.reduce(operator.iadd, doc, [])) + ) if 'hide-value' in metadata: return True @@ -2803,28 +3075,38 @@ def should_suppress_value_header(self) -> bool: def add_directive_header(self, sig: str) -> None: super().add_directive_header(sig) sourcename = self.get_sourcename() - if self.options.annotation is SUPPRESS or self.should_suppress_directive_header(): + if ( + self.options.annotation is SUPPRESS + or self.should_suppress_directive_header() + ): pass elif self.options.annotation: self.add_line(' :annotation: %s' % self.options.annotation, sourcename) else: if self.config.autodoc_typehints != 'none': # obtain type annotation for this attribute - annotations = get_type_hints(self.parent, None, - self.config.autodoc_type_aliases, - include_extras=True) + annotations = get_type_hints( + self.parent, + None, + self.config.autodoc_type_aliases, + include_extras=True, + ) if self.objpath[-1] in annotations: - if self.config.autodoc_typehints_format == "short": - objrepr = stringify_annotation(annotations.get(self.objpath[-1]), - "smart") - else: - objrepr = stringify_annotation(annotations.get(self.objpath[-1]), - "fully-qualified-except-typing") + mode = _get_render_mode(self.config.autodoc_typehints_format) + short_literals = self.config.python_display_short_literal_types + objrepr = stringify_annotation( + annotations.get(self.objpath[-1]), + mode, + short_literals=short_literals, + ) self.add_line(' :type: ' + objrepr, sourcename) try: - if (self.options.no_value or self.should_suppress_value_header() or - ismock(self.object)): + if ( + self.options.no_value + or self.should_suppress_value_header() + or ismock(self.object) + ): pass else: objrepr = object_description(self.object) @@ -2858,7 +3140,7 @@ def get_doc(self) -> list[list[str]] | None: try: # Disable `autodoc_inherit_docstring` temporarily to avoid to obtain # a docstring from the value which descriptor returns unexpectedly. - # ref: https://github.com/sphinx-doc/sphinx/issues/7805 + # See: https://github.com/sphinx-doc/sphinx/issues/7805 orig = self.config.autodoc_inherit_docstrings self.config.autodoc_inherit_docstrings = False return super().get_doc() @@ -2876,11 +3158,8 @@ def add_content(self, more_content: StringList | None) -> None: super().add_content(more_content) -class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc] - ClassLevelDocumenter): - """ - Specialized Documenter subclass for properties. - """ +class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore[misc] + """Specialized Documenter subclass for properties.""" objtype = 'property' member_order = 60 @@ -2890,7 +3169,7 @@ class PropertyDocumenter(DocstringStripSignatureMixin, # type: ignore[misc] @classmethod def can_document_member( - cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any, + cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any ) -> bool: if isinstance(parent, ClassDocumenter): if inspect.isproperty(member): @@ -2926,7 +3205,7 @@ def format_args(self, **kwargs: Any) -> str: return '' # update the annotations of the property getter - self.env.app.emit('autodoc-before-process-signature', func, False) + self._events.emit('autodoc-before-process-signature', func, False) # correctly format the arguments for a property return super().format_args(**kwargs) @@ -2950,23 +3229,25 @@ def add_directive_header(self, sig: str) -> None: return try: - signature = inspect.signature(func, - type_aliases=self.config.autodoc_type_aliases) + signature = inspect.signature( + func, type_aliases=self.config.autodoc_type_aliases + ) if signature.return_annotation is not Parameter.empty: - if self.config.autodoc_typehints_format == "short": - objrepr = stringify_annotation(signature.return_annotation, "smart") - else: - objrepr = stringify_annotation(signature.return_annotation, - "fully-qualified-except-typing") + mode = _get_render_mode(self.config.autodoc_typehints_format) + short_literals = self.config.python_display_short_literal_types + objrepr = stringify_annotation( + signature.return_annotation, mode, short_literals=short_literals + ) self.add_line(' :type: ' + objrepr, sourcename) except TypeError as exc: - logger.warning(__("Failed to get a function signature for %s: %s"), - self.fullname, exc) + logger.warning( + __('Failed to get a function signature for %s: %s'), self.fullname, exc + ) pass except ValueError: pass - def _get_property_getter(self) -> Callable | None: + def _get_property_getter(self) -> Callable[..., Any] | None: if safe_getattr(self.object, 'fget', None): # property return self.object.fget if safe_getattr(self.object, 'func', None): # cached_property @@ -2974,9 +3255,11 @@ def _get_property_getter(self) -> Callable | None: return None -def autodoc_attrgetter(app: Sphinx, obj: Any, name: str, *defargs: Any) -> Any: +def autodoc_attrgetter( + obj: Any, name: str, *defargs: Any, registry: SphinxComponentRegistry +) -> Any: """Alternative getattr() for types""" - for typ, func in app.registry.autodoc_attrgetters.items(): + for typ, func in registry.autodoc_attrgetters.items(): if isinstance(obj, typ): return func(obj, name, *defargs) @@ -2994,22 +3277,54 @@ def setup(app: Sphinx) -> ExtensionMetadata: app.add_autodocumenter(AttributeDocumenter) app.add_autodocumenter(PropertyDocumenter) - app.add_config_value('autoclass_content', 'class', 'env', ENUM('both', 'class', 'init')) - app.add_config_value('autodoc_member_order', 'alphabetical', 'env', - ENUM('alphabetical', 'bysource', 'groupwise')) - app.add_config_value('autodoc_class_signature', 'mixed', 'env', ENUM('mixed', 'separated')) - app.add_config_value('autodoc_default_options', {}, 'env') - app.add_config_value('autodoc_docstring_signature', True, 'env') - app.add_config_value('autodoc_mock_imports', [], 'env') - app.add_config_value('autodoc_typehints', "signature", 'env', - ENUM("signature", "description", "none", "both")) - app.add_config_value('autodoc_typehints_description_target', 'all', 'env', - ENUM('all', 'documented', 'documented_params')) - app.add_config_value('autodoc_type_aliases', {}, 'env') - app.add_config_value('autodoc_typehints_format', "short", 'env', - ENUM("fully-qualified", "short")) - app.add_config_value('autodoc_warningiserror', True, 'env') - app.add_config_value('autodoc_inherit_docstrings', True, 'env') + app.add_config_value( + 'autoclass_content', + 'class', + 'env', + types=ENUM('both', 'class', 'init'), + ) + app.add_config_value( + 'autodoc_member_order', + 'alphabetical', + 'env', + types=ENUM('alphabetical', 'bysource', 'groupwise'), + ) + app.add_config_value( + 'autodoc_class_signature', + 'mixed', + 'env', + types=ENUM('mixed', 'separated'), + ) + app.add_config_value('autodoc_default_options', {}, 'env', types=frozenset({dict})) + app.add_config_value( + 'autodoc_docstring_signature', True, 'env', types=frozenset({bool}) + ) + app.add_config_value( + 'autodoc_mock_imports', [], 'env', types=frozenset({list, tuple}) + ) + app.add_config_value( + 'autodoc_typehints', + 'signature', + 'env', + types=ENUM('signature', 'description', 'none', 'both'), + ) + app.add_config_value( + 'autodoc_typehints_description_target', + 'all', + 'env', + types=ENUM('all', 'documented', 'documented_params'), + ) + app.add_config_value('autodoc_type_aliases', {}, 'env', types=frozenset({dict})) + app.add_config_value( + 'autodoc_typehints_format', + 'short', + 'env', + types=ENUM('fully-qualified', 'short'), + ) + app.add_config_value('autodoc_warningiserror', True, 'env', types=frozenset({bool})) + app.add_config_value( + 'autodoc_inherit_docstrings', True, 'env', types=frozenset({bool}) + ) app.add_event('autodoc-before-process-signature') app.add_event('autodoc-process-docstring') app.add_event('autodoc-process-signature') @@ -3020,4 +3335,7 @@ def setup(app: Sphinx) -> ExtensionMetadata: app.setup_extension('sphinx.ext.autodoc.type_comment') app.setup_extension('sphinx.ext.autodoc.typehints') - return {'version': sphinx.__display_version__, 'parallel_read_safe': True} + return { + 'version': sphinx.__display_version__, + 'parallel_read_safe': True, + } diff --git a/src/sage_setup/cython_options.py b/src/sage_setup/cython_options.py index 9725ce0e1af..078d670983a 100644 --- a/src/sage_setup/cython_options.py +++ b/src/sage_setup/cython_options.py @@ -10,7 +10,11 @@ def compiler_directives(profile: bool): auto_pickle=False, # Do not create __test__ dictionary automatically from docstrings autotestdict=False, - binding=False, + # When enabled, functions will be bound to an instance when looked up as a + # class attribute (hence the name) and will emulate the attributes of + # Python functions, including introspections like argument names and + # annotations + binding=True, c_api_binop_methods=True, # Do not check for division by 0 (this is about 35% quicker than with check) cdivision=True, diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index caec16fa51d..c24d77e15f6 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -82,7 +82,6 @@ scripts = bin/sage-notebook bin/sage-num-threads.py bin/sage-preparse - bin/sage-python bin/sage-run bin/sage-run-cython bin/sage-startuptime.py diff --git a/subprojects/maxima.wrap b/subprojects/maxima.wrap new file mode 100644 index 00000000000..b413d7bb99e --- /dev/null +++ b/subprojects/maxima.wrap @@ -0,0 +1,12 @@ +[wrap-file] +source_url = https://sourceforge.net/projects/maxima/files/Maxima-source/5.47.0-source/maxima-5.47.0.tar.gz/download +source_hash = 9104021b24fd53e8c03a983509cb42e937a925e8c0c85c335d7709a14fd40f7a +source_filename = maxima-5.47.0.tar.gz +directory = maxima-5.47.0 +patch_directory = maxima +diff_files = maxima/configure.patch + +#[wrap-git] +#url = https://git.code.sf.net/p/maxima/code +#revision = master +#depth = 1 diff --git a/subprojects/packagefiles/ecl/src/meson.build b/subprojects/packagefiles/ecl/src/meson.build index ec01cd1ecbb..e19c9ebf3d8 100644 --- a/subprojects/packagefiles/ecl/src/meson.build +++ b/subprojects/packagefiles/ecl/src/meson.build @@ -1,16 +1,36 @@ +libpath = meson.current_build_dir() + '/dist/usr/local/lib64' +ecldir = meson.current_build_dir() + '/dist/usr/local/lib64/ecl-24.5.10' +include_path = meson.current_build_dir() + '/build' + proj = mod.add_project('configure', configure_options : [ + # ecl embeds the include path, so we have to set it to the *installed* path + # workaround for https://gitlab.com/embeddable-common-lisp/ecl/-/issues/780 + '--includedir=' + include_path, '--enable-manual=no', '--enable-unicode=yes', '--with-defsystem', ], + env: { + 'LDFLAGS': '-Wl,-rpath,' + libpath + ' -L' + libpath, + # Workaround for https://gitlab.com/embeddable-common-lisp/ecl/-/issues/779 + # Need to tell ECL where to find the fas files after installation + 'CFLAGS': '-DECLDIR=\"' + ecldir + '\"', + } ) ecl_dep = proj.dependency('ecl') # Ugly workaround to include the rpath in the dependency # https://github.com/mesonbuild/meson/issues/12970 -ecl_rpath_dep = declare_dependency(link_args: '-Wl,-rpath,' + meson.current_build_dir() + '/dist/usr/local/lib64') +ecl_rpath_dep = declare_dependency( + link_args: '-Wl,-rpath,' + libpath + ' -L' + libpath, + include_directories: [include_directories('build')], +) ecl_dep = declare_dependency( dependencies : [ecl_dep, ecl_rpath_dep], + variables: { + 'ecl_bin' : meson.current_build_dir() + '/dist/usr/local/bin/ecl', + 'ecldir' : ecldir, + }, ) meson.override_dependency('ecl', ecl_dep) diff --git a/subprojects/packagefiles/maxima/configure.patch b/subprojects/packagefiles/maxima/configure.patch new file mode 100644 index 00000000000..5e8af2db461 --- /dev/null +++ b/subprojects/packagefiles/maxima/configure.patch @@ -0,0 +1,22 @@ +diff --git a/configure b/configure +old mode 100755 +new mode 100644 +index 6716f3a04a6..732dcfeae8b +--- a/configure ++++ b/configure +@@ -7092,15 +7092,6 @@ if test x"${ccl64}" = xtrue ; then + fi + fi + +-if test x"${ecl}" = xtrue ; then +- if test x"$srcdir" = x"." ; then +- echo "Compiling maxima using \"${ECL_NAME}\"" +- else +- echo "ECL enabled. Executable name: \"${ECL_NAME}\"" +- as_fn_error $? "For ECL out-of-tree builds aren't supported. See src/maxima.system for details." "$LINENO" 5 +- fi +-fi +- + if test x"${abcl}" = xtrue ; then + if test x"$srcdir" = x"." ; then + echo "Compiling maxima using \"${ABCL_JAR}\"" diff --git a/subprojects/packagefiles/maxima/meson.build b/subprojects/packagefiles/maxima/meson.build new file mode 100644 index 00000000000..7f1316e4962 --- /dev/null +++ b/subprojects/packagefiles/maxima/meson.build @@ -0,0 +1,43 @@ +project('maxima', 'c', + meson_version : '>=0.63.0', +) + +mod = import('unstable-external_project') + +cc = meson.get_compiler('c') +ecl = find_program('ecl', required: false) +dependencies = [] +if ecl.found() + ecl = ecl.full_path() +else + ecl_proj = subproject('ecl') + ecl = ecl_proj.get_variable('ecl_dep').get_variable('ecl_bin') + # It is not possible to have an external project directly depend on another external project (actually on an InternalDependency) + # So we need to create a dummy library as the middleman + ec_lib = library('ecl_lib', + dependencies : [ecl_proj.get_variable('ecl_dep').partial_dependency(sources : true)], + ) + dependencies += [ec_lib] +endif +proj = mod.add_project('configure', + configure_options : [ + '--enable-ecl', + '--with-ecl=' + ecl, + '--disable-build-docs', + # Maxima configure checks for git and, if it finds it, uses + # versions information from the repo. See #15529. We disable this. + 'git_found=false', + ], + depends: dependencies, +) + +maxima_fas_dep = proj.dependency('maxima').partial_dependency(sources : true) +maxima_dep = declare_dependency( + variables: { + 'MAXIMA_FAS': meson.current_build_dir() + '/build/src/binary-ecl/maxima.fas', + 'MAXIMA_SHARE': meson.current_build_dir() + '/dist/usr/local/share/maxima/5.47.0/share', + 'MAXIMA_BIN': meson.current_build_dir() + '/dist/usr/local/bin/maxima', + }, + dependencies: maxima_fas_dep +) +meson.override_dependency('maxima', maxima_dep) diff --git a/uv.lock b/uv.lock index 606a880b80c..6c5ab748b2c 100644 --- a/uv.lock +++ b/uv.lock @@ -2246,7 +2246,6 @@ dependencies = [ { name = "ipython" }, { name = "ipywidgets" }, { name = "jupyter-client" }, - { name = "lrcalc", marker = "sys_platform != 'win32'" }, { name = "matplotlib" }, { name = "memory-allocator" }, { name = "mpmath" }, @@ -2268,6 +2267,9 @@ dependencies = [ ] [package.optional-dependencies] +extra = [ + { name = "lrcalc", marker = "sys_platform != 'win32'" }, +] r = [ { name = "rpy2" }, ] @@ -2313,7 +2315,7 @@ requires-dist = [ { name = "ipython", specifier = ">=8.9.0" }, { name = "ipywidgets", specifier = ">=7.5.1" }, { name = "jupyter-client" }, - { name = "lrcalc", marker = "sys_platform != 'win32'", specifier = "~=2.1" }, + { name = "lrcalc", marker = "extra == 'extra'", specifier = "~=2.1" }, { name = "matplotlib", specifier = ">=3.7.0" }, { name = "memory-allocator" }, { name = "mpmath", specifier = ">=1.1.0" }, @@ -2335,7 +2337,7 @@ requires-dist = [ { name = "traitlets" }, { name = "typing-extensions", marker = "python_full_version < '3.11'", specifier = ">=4.4.0" }, ] -provides-extras = ["r"] +provides-extras = ["r", "extra"] [package.metadata.requires-dev] dev = [ From b7cf06ff987984429a5eed455cb74bd02493bd3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Sat, 2 Aug 2025 23:07:41 +0200 Subject: [PATCH 8/9] 40519 new --- build/pkgs/gap_packages/spkg-install.in | 10 +++++++++- build/pkgs/qhull/patches/qhull_cmake.patch | 22 ++++++++++++++++++++++ build/pkgs/symengine/package-version.txt | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 build/pkgs/qhull/patches/qhull_cmake.patch diff --git a/build/pkgs/gap_packages/spkg-install.in b/build/pkgs/gap_packages/spkg-install.in index c67a1176a69..314a784c5c7 100644 --- a/build/pkgs/gap_packages/spkg-install.in +++ b/build/pkgs/gap_packages/spkg-install.in @@ -92,7 +92,7 @@ install_compiled_pkg() # # These packages have an old ./configure that take the GAP_ROOT as a positional # argument -for pkg in cohomolo crypting grape guava orb datastructures +for pkg in cohomolo crypting grape orb datastructures do echo "Building GAP package $pkg" CFLAGS="$CFLAGS -Wno-implicit-function-declaration" @@ -104,6 +104,14 @@ do cd "$PKG_SRC_DIR" done +echo "Building GAP package guava" +export CFLAGS="-std=gnu17 $CFLAGS -Wno-implicit-function-declaration" +cd "$PKG_SRC_DIR/guava" +./configure "$GAP_ROOT" +sdh_make +install_compiled_pkg "guava" +cd "$PKG_SRC_DIR" + # These packages have a new-style autoconf ./configure # that takes --with-gaproot diff --git a/build/pkgs/qhull/patches/qhull_cmake.patch b/build/pkgs/qhull/patches/qhull_cmake.patch new file mode 100644 index 00000000000..575c220b7d2 --- /dev/null +++ b/build/pkgs/qhull/patches/qhull_cmake.patch @@ -0,0 +1,22 @@ +*** src/CMakeLists.txt.orig Thu May 8 13:21:24 2025 +--- src/CMakeLists.txt Thu May 8 13:25:39 2025 +*************** +*** 67,74 **** + # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ + # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ + + project(qhull) +- cmake_minimum_required(VERSION 3.0) + + # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt + # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm +--- 67,75 ---- + # $Id: //main/2019/qhull/CMakeLists.txt#21 $$Change: 3039 $ + # $DateTime: 2020/09/03 21:26:22 $$Author: bbarber $ + ++ cmake_minimum_required(VERSION 3.25...4.0.3) ++ + project(qhull) + + # Define qhull_VERSION in README.txt, Announce.txt, qh-get.htm, CMakeLists.txt + # qhull-zip.sh (twice), qhull-wiki.md, qhull-news.htm, File_id.diz, index.htm diff --git a/build/pkgs/symengine/package-version.txt b/build/pkgs/symengine/package-version.txt index a8839f70de0..0548fb4e9b2 100644 --- a/build/pkgs/symengine/package-version.txt +++ b/build/pkgs/symengine/package-version.txt @@ -1 +1 @@ -0.11.2 \ No newline at end of file +0.14.0 \ No newline at end of file From e7f3ac9b92220af6aa30e97885c2928b48b819e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Moreno-Soc=C3=ADas?= Date: Sat, 2 Aug 2025 23:49:11 +0200 Subject: [PATCH 9/9] 40519 new --- build/pkgs/symengine/checksums.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/symengine/checksums.ini b/build/pkgs/symengine/checksums.ini index 72907d5595e..35f51ec6115 100644 --- a/build/pkgs/symengine/checksums.ini +++ b/build/pkgs/symengine/checksums.ini @@ -1,4 +1,4 @@ tarball=symengine-VERSION.tar.gz -sha1=2dfee07108509963f3dbe3d9cad9de76d85e551f -sha256=f6972acd6a65354f6414e69460d2e175729470632bdac05919bc2f7f32e48cbd +sha1=e53aa2677bcad5a5dc075a94d4a4f9ef95b5fe07 +sha256=11c5f64e9eec998152437f288b8429ec001168277d55f3f5f1df78e3cf129707 upstream_url=https://github.com/symengine/symengine/releases/download/vVERSION/symengine-VERSION.tar.gz