From 10fea7f48f53267c74d29a4887440035b8d7cbc3 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 19 Apr 2025 10:24:21 +0000 Subject: [PATCH 01/21] Meson: add building of documentation as target --- .github/workflows/doc-build.yml | 168 ++++-------- pyproject.toml | 3 +- src/build-docs.py | 4 + src/doc/en/reference/conf_sub.py | 8 +- src/doc/meson.build | 122 +++++++++ src/meson.build | 3 + src/sage_docbuild/__main__.py | 80 +++--- src/sage_docbuild/build_options.py | 12 +- src/sage_docbuild/builders.py | 393 +++++++++++------------------ 9 files changed, 394 insertions(+), 399 deletions(-) create mode 100644 src/build-docs.py create mode 100644 src/doc/meson.build diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 9ffbf874d7a..63c77b67ae2 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -16,15 +16,6 @@ on: - develop workflow_dispatch: # Allow to run manually - inputs: - platform: - description: 'Platform' - required: true - default: 'ubuntu-noble-standard' - docker_tag: - description: 'Docker tag' - required: true - default: 'dev' concurrency: # Cancel previous runs of this workflow for the same branch @@ -32,94 +23,53 @@ concurrency: cancel-in-progress: true env: - # Same as in build.yml - TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-incremental" - BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-with-targets:ci" - FROM_DOCKER_REPOSITORY: "ghcr.io/sagemath/sage/" - FROM_DOCKER_TARGET: "with-targets" - FROM_DOCKER_TAG: ${{ github.event.inputs.docker_tag || 'dev'}} - EXTRA_CONFIGURE_ARGS: --enable-fat-binary + PYTHON_VERSION: 3.11 jobs: build-doc: runs-on: ubuntu-latest - services: - # https://docs.docker.com/build/ci/github-actions/local-registry/ - registry: - image: registry:2 - ports: - - 5000:5000 steps: - - name: Maximize build disk space - uses: easimon/maximize-build-space@v10 - with: - # need space in /var for Docker images - root-reserve-mb: 30000 - remove-dotnet: true - remove-android: true - remove-haskell: true - remove-codeql: true - remove-docker-images: true - name: Checkout uses: actions/checkout@v4 - - name: Install test prerequisites - # From docker.yml - run: | - sudo DEBIAN_FRONTEND=noninteractive apt-get update - sudo DEBIAN_FRONTEND=noninteractive apt-get install tox - sudo apt-get clean - df -h + - name: Merge CI fixes from sagemath/sage run: | - mkdir -p upstream - .ci/merge-fixes.sh 2>&1 | tee upstream/ci_fixes.log + .ci/merge-fixes.sh env: GH_TOKEN: ${{ github.token }} - SAGE_CI_FIXES_FROM_REPOSITORIES: ${{ vars.SAGE_CI_FIXES_FROM_REPOSITORIES }} - - # Building - - - name: Generate Dockerfile - # From docker.yml - run: | - tox -e ${{ env.TOX_ENV }} - cp .tox/${{ env.TOX_ENV }}/Dockerfile . - env: - # Only generate the Dockerfile, do not run 'docker build' here - DOCKER_TARGETS: "" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - name: Cache conda packages + uses: actions/cache@v4 with: - driver-opts: network=host - - - name: Build Docker image - id: image - uses: docker/build-push-action@v6 + path: ~/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ hashFiles('environment-${{ env.PYTHON_VERSION }}-linux.yml') }} + + - name: Compiler cache + uses: hendrikmuhs/ccache-action@v1.2 with: - # push and load may not be set together at the moment - push: true - load: false - context: . - tags: ${{ env.BUILD_IMAGE }} - target: with-targets - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - NUMPROC=6 - USE_MAKEFLAGS=-k V=0 SAGE_NUM_THREADS=4 --output-sync=recurse - TARGETS_PRE=build/make/Makefile - TARGETS=ci-build-with-fallback + key: ${{ runner.os }}-meson-${{ env.PYTHON_VERSION }} - - name: Start container - id: container - # Try to continue when "exporting to GitHub Actions Cache" failed with timeout + - name: Setup Conda environment + uses: conda-incubator/setup-miniconda@v3 + with: + python-version: ${{ env.PYTHON_VERSION }} + # Disabled for now due to + # https://github.com/conda-incubator/setup-miniconda/issues/379 + # miniforge-version: latest + use-mamba: true + channels: conda-forge + channel-priority: true + activate-environment: sage-dev + environment-file: environment-${{ env.PYTHON_VERSION }}-linux.yml + + - name: Build Sage + shell: bash -l {0} run: | - docker run --name BUILD -dit \ - --mount type=bind,src=$(pwd),dst=$(pwd) \ - --workdir $(pwd) \ - ${{ env.BUILD_IMAGE }} /bin/sh - + export LIB="$LIB;$CONDA_PREFIX\\Library\\lib" + export INCLUDE="$INCLUDE;$CONDA_PREFIX\\Library\\include" + pip install --no-build-isolation --config-settings=builddir=builddir . -v + # # On pull request and push to develop events # @@ -164,8 +114,8 @@ jobs: # mathjax path in old doc (regex) mathjax_path_from="[-./A-Za-z_]*/tex-chtml[.]js?v=[0-9a-f]*" # mathjax path in new doc - mathjax_path_to=$(docker exec -e SAGE_USE_CDNS=yes BUILD /sage/sage -python -c "from sage_docbuild.conf import mathjax_path; print(mathjax_path)") - new_version=$(docker exec BUILD cat src/VERSION.txt) + mathjax_path_to=$(SAGE_USE_CDNS=yes python -c "from sage_docbuild.conf import mathjax_path; print(mathjax_path)") + new_version=$(cat src/VERSION.txt) # Wipe out chronic diffs between old doc and new doc (cd doc && \ find . -name "*.html" | xargs sed -i -e '/class="sidebar-brand-text"/ s/Sage [0-9a-z.]* /Sage '"$new_version"' /' \ @@ -185,20 +135,15 @@ jobs: git add -A && git commit --quiet -m 'old') fi - - name: Build doc + - name: Build documentation id: docbuild - if: steps.container.outcome == 'success' && !startsWith(github.ref, 'refs/tags/') - # Always non-incremental because of the concern that - # incremental docbuild may introduce broken links (inter-file references) though build succeeds + if: steps.worktree.outcome == 'success' + shell: bash -l {0} run: | - export GITHUB_REF=${{ github.ref }} - export PR_SHA=${{ github.event.pull_request.head.sha }} - export MAKE="make -j5 --output-sync=recurse" SAGE_NUM_THREADS=5 - make doc-clean doc-uninstall - export SAGE_USE_CDNS=yes - export SAGE_DOCBUILD_OPTS="--include-tests-blocks" - ./config.status && make sagemath_doc_html-no-deps - shell: sh .ci/docker-exec-script.sh BUILD /sage {0} + meson compile -C builddir doc-html + env: + SAGE_USE_CDNS: yes + SAGE_DOCBUILD_OPTS: "--include-tests-blocks" - name: Copy doc id: copy @@ -209,12 +154,7 @@ jobs: if [ -d "doc/html" ]; then rm -rf doc/html fi - # Simpler "docker cp --follow-link ... doc" does not work - mkdir -p doc - mkdir -p temp - docker cp --follow-link BUILD:/sage/local/share/doc/sage/html temp - docker cp --follow-link BUILD:/sage/local/share/doc/sage/index.html temp - cp -r -L temp/* doc/ + cp -r builddir/src/doc doc/ # Check if we are on pull request event PR_NUMBER="" if [[ -n "$GITHUB_REF" ]]; then @@ -275,20 +215,14 @@ jobs: - name: Build live doc id: buildlivedoc if: startsWith(github.ref, 'refs/tags/') + shell: bash -l {0} run: | - # Avoid running out of disk space - rm -rf upstream - export MAKE="make -j5 --output-sync=recurse" SAGE_NUM_THREADS=5 - export PATH="build/bin:$PATH" - eval $(sage-print-system-package-command auto update) - eval $(sage-print-system-package-command auto --yes --no-install-recommends install zip) - eval $(sage-print-system-package-command auto --spkg --yes --no-install-recommends install git texlive texlive_luatex free_fonts xindy) - export SAGE_USE_CDNS=yes - export SAGE_LIVE_DOC=yes - export SAGE_JUPYTER_SERVER=binder:sagemath/sage-binder-env/dev - make doc-clean doc-uninstall - ./config.status && make sagemath_doc_html-no-deps sagemath_doc_pdf-no-deps - shell: sh .ci/docker-exec-script.sh BUILD /sage {0} + meson compile -C builddir doc-html + env: + SAGE_USE_CDNS: yes + SAGE_LIVE_DOC: yes + SAGE_JUPYTER_SERVER: binder:sagemath/sage-binder-env/dev + SAGE_DOCBUILD_OPTS: "--include-tests-blocks" - name: Copy live doc id: copylivedoc @@ -296,9 +230,9 @@ jobs: run: | mkdir -p ./livedoc # We copy everything to a local folder - docker cp --follow-link BUILD:/sage/local/share/doc/sage/html livedoc - docker cp --follow-link BUILD:/sage/local/share/doc/sage/pdf livedoc - docker cp --follow-link BUILD:/sage/local/share/doc/sage/index.html livedoc + cp -r builddir/src/doc/html livedoc/ + cp -r builddir/src/doc/pdf livedoc/ + cp builddir/src/doc/index.html livedoc/ zip -r livedoc.zip livedoc - name: Upload live doc diff --git a/pyproject.toml b/pyproject.toml index 6f242e11b67..af7e1fd8450 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -169,7 +169,8 @@ test = [ ] docs = [ "sphinx", - "sphinx-inline-tabs", + "sphinx-copybutton", + "sphinx-inline-tabs", "furo", ] lint = [ diff --git a/src/build-docs.py b/src/build-docs.py new file mode 100644 index 00000000000..2fa1c4f718e --- /dev/null +++ b/src/build-docs.py @@ -0,0 +1,4 @@ +from sage_docbuild.__main__ import main + +if __name__ == "__main__": + main() diff --git a/src/doc/en/reference/conf_sub.py b/src/doc/en/reference/conf_sub.py index c7adc1da994..e4b6b595b29 100644 --- a/src/doc/en/reference/conf_sub.py +++ b/src/doc/en/reference/conf_sub.py @@ -11,10 +11,10 @@ # serve to show the default. import os -from sage.env import SAGE_DOC_SRC, SAGE_DOC -from sage_docbuild.conf import release, exclude_patterns -from sage_docbuild.conf import * +from sage.env import SAGE_DOC, SAGE_DOC_SRC +from sage_docbuild.conf import * +from sage_docbuild.conf import exclude_patterns for tag in feature_tags(): tags.add(tag) @@ -31,7 +31,7 @@ ref_out = os.path.join(SAGE_DOC, 'html', 'en', 'reference') # We use the main document's title, if we can find it. -rst_file = open('index.rst', 'r') +rst_file = open('index.rst', 'r', encoding='utf-8') rst_lines = rst_file.read().splitlines() rst_file.close() diff --git a/src/doc/meson.build b/src/doc/meson.build new file mode 100644 index 00000000000..d6be7b7122d --- /dev/null +++ b/src/doc/meson.build @@ -0,0 +1,122 @@ +# Clean target +# clean = custom_target( +# 'clean', +# output: [], +# command: [ +# 'sh', '-c', +# ''' +# rm -rf en/reference/*/sage +# rm -rf en/reference/documentation/sage_docbuild +# rm -rf en/reference/sage +# rm -f common/*.pyc +# ''' +# ] +# ) + +# Generate sources at build time +# doc_src = custom_target( +# 'doc-src', +# output: ['en/reference/repl/options.txt'], +# command: [ +# 'sh', '-c', +# ''' +# mkdir -p en/reference/repl +# sage -advanced > en/reference/repl/options.txt +# ''' +# ] +# ) + + + +references = run_command( + py, + [ + src / 'build-docs.py', + '--all-documents', + 'reference', + '--source', meson.current_source_dir() + ], + check: true, +).stdout().strip() + +reference_inventory = [] +reference_html = [] +reference_pdf = [] +bibliography = [] +foreach type : ['inventory', 'html', 'pdf'] + foreach ref : references.splitlines() + short_ref = ref.split('/')[1] + deps = [] + if type == 'html' or type == 'pdf' + deps += reference_inventory + endif + if short_ref != 'references' + deps += bibliography + endif + target = custom_target( + 'doc-' + type + '-reference-' + short_ref, + output: [type + short_ref], + command: [ + py, + src / 'build-docs.py', + '--no-pdf-links', + ref, + type, + '-o', '@OUTDIR@', + '--source', meson.current_source_dir() + ], + depends: deps, + ) + if short_ref == 'references' + bibliography += target + endif + if type == 'inventory' + reference_inventory += target + elif type == 'html' + reference_html += target + elif type == 'pdf' + reference_pdf += target + endif + endforeach +endforeach + +other_documents = run_command( + py, + [ + src / 'build-docs.py', + '--all-documents', + 'all', + '--source', meson.current_source_dir() + ], + check: true, +).stdout().strip() +other_documents_html = [] +other_documents_pdf = [] +foreach type : ['html', 'pdf'] + foreach doc : other_documents.splitlines() + short_doc = doc.replace('/', '-') + target = custom_target( + 'doc-' + type + '-other-' + short_doc, + output: [type + short_doc], + command: [ + py, + src / 'build-docs.py', + '--no-pdf-links', + doc, + type, + '-o', '@OUTDIR@', + '--source', meson.current_source_dir() + ], + depends: reference_inventory, + ) + if type == 'html' + other_documents_html += target + elif type == 'pdf' + other_documents_pdf += target + endif + endforeach +endforeach + +# Custom target for building the complete documentation +alias_target('doc-html', [reference_html, other_documents_html]) +alias_target('doc-pdf', [reference_pdf, other_documents_pdf]) diff --git a/src/meson.build b/src/meson.build index ddd2a82d047..8efd56d36a9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -157,5 +157,8 @@ inc_ext = include_directories('sage/ext') inc_partn_ref2 = include_directories('sage/groups/perm_gps/partn_ref2') inc_src = include_directories('.') +src = meson.current_source_dir() + # Submodules subdir('sage') +subdir('doc') diff --git a/src/sage_docbuild/__main__.py b/src/sage_docbuild/__main__.py index a7b7b39880b..6a180efc921 100644 --- a/src/sage_docbuild/__main__.py +++ b/src/sage_docbuild/__main__.py @@ -72,15 +72,22 @@ en/reference. If ARG is 'all', list all main documents """ -import logging import argparse +import logging import os -import shlex import sys +from pathlib import Path + import sphinx.ext.intersphinx -from sage.env import SAGE_DOC_SRC -from .builders import DocBuilder, ReferenceBuilder, get_builder, get_documents + from . import build_options +from .build_options import BuildOptions +from .builders import ( + DocBuilder, + get_all_documents, + get_all_reference_documents, + get_builder, +) logger = logging.getLogger(__name__) @@ -161,7 +168,7 @@ def help_documents(): s += "\n" if 'reference' in docs: s += "Other valid document names take the form 'reference/DIR', where\n" - s += "DIR is a subdirectory of SAGE_DOC_SRC/en/reference/.\n" + s += "DIR is a subdirectory of src/doc/en/reference/.\n" s += "This builds just the specified part of the reference manual.\n" s += "DOCUMENT may also have the form 'file=/path/to/FILE', which builds\n" s += "the documentation for the specified file.\n" @@ -251,21 +258,6 @@ def __call__(self, parser, namespace, values, option_string=None): print(help_formats(), end="") if self.dest == 'commands': print(help_commands(values), end="") - if self.dest == 'all_documents': - if values == 'reference': - b = ReferenceBuilder('reference') - refdir = os.path.join(os.environ['SAGE_DOC_SRC'], 'en', b.name) - s = b.get_all_documents(refdir) - # Put the bibliography first, because it needs to be built first: - s.remove('reference/references') - s.insert(0, 'reference/references') - elif values == 'all': - s = get_documents() - # Put the reference manual first, because it needs to be built first: - s.remove('reference') - s.insert(0, 'reference') - for d in s: - print(d) setattr(namespace, 'printed_list', 1) sys.exit(0) @@ -339,7 +331,11 @@ def setup_parser(): type=int, default=1, metavar="LEVEL", action="store", help="report progress at LEVEL=0 (quiet), 1 (normal), 2 (info), or 3 (debug); does not affect children") + standard.add_argument("-s", "--source", dest="source_dir", type=Path, + default=None, metavar="DIR", action="store", + help="directory containing the documentation source files") standard.add_argument("-o", "--output", dest="output_dir", default=None, + type=Path, metavar="DIR", action="store", help="if DOCUMENT is a single file ('file=...'), write output to this directory") @@ -359,7 +355,6 @@ def setup_parser(): advanced.add_argument("--all-documents", dest="all_documents", type=str, metavar="ARG", choices=['all', 'reference'], - action=help_wrapper, help="if ARG is 'reference', list all subdocuments" " of en/reference. If ARG is 'all', list all main" " documents") @@ -456,8 +451,33 @@ def fetch_inventory(self, app, uri, inv): def main(): # Parse the command-line. parser = setup_parser() - args = parser.parse_args() - DocBuilder._options = args + args: BuildOptions = parser.parse_args() # type: ignore + + # Check that the docs source directory exists + if args.source_dir is None: + args.source_dir = Path(os.environ.get('SAGE_DOC_SRC', 'src/doc')) + if not args.source_dir.is_dir(): + parser.error(f"Source directory {args.source_dir} does not exist.") + + if args.all_documents: + if args.all_documents == 'reference': + docs = get_all_reference_documents(args.source_dir / 'en') + elif args.all_documents == 'all': + docs = get_all_documents(args.source_dir) + else: + parser.error(f"Unknown argument {args.all_documents} for --all-documents.") + for d in docs: + print(d.as_posix()) + sys.exit(0) + + # Check that the docs output directory exists + if args.output_dir is None: + args.output_dir = Path(os.environ.get('SAGE_DOC', 'src/doc')) + if not args.output_dir.exists(): + try: + args.output_dir.mkdir(parents=True) + except Exception as e: + parser.error(f"Failed to create output directory {args.output_dir}: {e}") # Get the name and type (target format) of the document we are # trying to build. @@ -465,20 +485,16 @@ def main(): if not name or not typ: parser.print_help() sys.exit(1) - elif name == 'all': - sys.exit(os.system(f'cd {shlex.quote(SAGE_DOC_SRC)} ' - f'&& ${{MAKE:-make}} -j${{SAGE_NUM_THREADS_PARALLEL:-1}} doc-{typ}')) # Set up module-wide logging. setup_logger(args.verbose, args.color) def excepthook(*exc_info): logger.error('Error building the documentation.', exc_info=exc_info) - if build_options.INCREMENTAL_BUILD: - logger.error(''' - Note: incremental documentation builds sometimes cause spurious - error messages. To be certain that these are real errors, run - "make doc-clean doc-uninstall" first and try again.''') + logger.info(''' +Note: incremental documentation builds sometimes cause spurious +error messages. To be certain that these are real errors, run +"make doc-clean doc-uninstall" first and try again.''') sys.excepthook = excepthook @@ -511,7 +527,7 @@ def excepthook(*exc_info): # Set up Intersphinx cache _ = IntersphinxCache() - builder = get_builder(name) + builder = get_builder(name, args) if not args.no_prune_empty_dirs: # Delete empty directories. This is needed in particular for empty diff --git a/src/sage_docbuild/build_options.py b/src/sage_docbuild/build_options.py index 4857c1ed125..7be118e3c12 100644 --- a/src/sage_docbuild/build_options.py +++ b/src/sage_docbuild/build_options.py @@ -4,12 +4,10 @@ This module defines options for building Sage documentation. """ +import argparse import os -import re +from pathlib import Path -from sage.env import SAGE_DOC_SRC, SAGE_DOC - -LANGUAGES = [d for d in os.listdir(SAGE_DOC_SRC) if re.match('^[a-z][a-z]$', d)] SPHINXOPTS = "" PAPER = "" OMIT = ["introspect"] # docs/dirs to omit when listing and building 'all' @@ -26,7 +24,9 @@ # Number of threads to use for parallel-building the documentation. NUM_THREADS = int(os.environ.get('SAGE_NUM_THREADS', 1)) -INCREMENTAL_BUILD = os.path.isdir(SAGE_DOC) - # Error out on errors ABORT_ON_ERROR = True + +class BuildOptions(argparse.Namespace): + source_dir: Path + output_dir: Path diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index ab39d93c280..ef3af17db87 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -70,14 +70,12 @@ import subprocess import sys import time -import types import warnings +from pathlib import Path +from typing import Generator, Literal -import sage.all -from sage.misc.cachefunc import cached_method -# Do not import SAGE_DOC globally as it interferes with doctesting with a random replacement -from sage.env import SAGE_DOC_SRC, SAGE_SRC, DOT_SAGE from . import build_options +from .build_options import BuildOptions from .utils import build_many as _build_many logger = logging.getLogger(__name__) @@ -181,24 +179,19 @@ def f(self, *args, **kwds): class DocBuilder(): - def __init__(self, name, lang='en'): + def __init__(self, name: str, options: BuildOptions, lang: str='en'): """ INPUT: - - ``name`` -- the name of a subdirectory in SAGE_DOC_SRC, such as - 'tutorial' or 'bordeaux_2008' + - ``name`` -- the name of a subdirectory in ``doc/``, such as + 'tutorial' or 'installation' - ``lang`` -- (default "en") the language of the document. """ - doc = name.split(os.path.sep) - - if doc[0] in build_options.LANGUAGES: - lang = doc[0] - doc.pop(0) - - self.name = os.path.join(*doc) + self.name = name self.lang = lang - self.dir = os.path.join(SAGE_DOC_SRC, self.lang, self.name) + self.dir = options.source_dir / self.lang / self.name + self._options = options def _output_dir(self, type): """ @@ -214,12 +207,11 @@ def _output_dir(self, type): sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/tutorial' """ - from sage.env import SAGE_DOC - d = os.path.join(SAGE_DOC, type, self.lang, self.name) - os.makedirs(d, exist_ok=True) - return d + dir = self._options.output_dir / type / self.lang / self.name + dir.mkdir(parents=True, exist_ok=True) + return dir - def _doctrees_dir(self): + def _doctrees_dir(self) -> Path: """ Return the directory where the doctrees are stored. @@ -233,10 +225,9 @@ def _doctrees_dir(self): sage: b._doctrees_dir() # optional - sagemath_doc_html '.../doctrees/en/tutorial' """ - from sage.env import SAGE_DOC - d = os.path.join(SAGE_DOC, 'doctrees', self.lang, self.name) - os.makedirs(d, exist_ok=True) - return d + dir = self._options.output_dir / 'doctrees' / self.lang / self.name + dir.mkdir(parents=True, exist_ok=True) + return dir def _output_formats(self): """ @@ -278,7 +269,7 @@ def pdf(self): if self.name == 'reference': # recover maths in tex, undoing what Sphinx did (trac #29993) - tex_file = os.path.join(tex_dir, 'reference.tex') + tex_file = tex_dir / 'reference.tex' with open(tex_file) as f: ref = f.read() ref = re.sub(r'\\textbackslash{}', r'\\', ref) @@ -343,89 +334,6 @@ def build_other_doc(args): getattr(get_builder(document), name)(*args, **kwds) -class AllBuilder(): - """ - A class used to build all of the documentation. - """ - def __getattr__(self, attr): - """ - For any attributes not explicitly defined, we just go through - all of the documents and call their attr. For example, - 'AllBuilder().json()' will go through all of the documents - and call the json() method on their builders. - """ - from functools import partial - return partial(self._wrapper, attr) - - def _wrapper(self, name, *args, **kwds): - """ - This is the function which goes through all of the documents - and does the actual building. - """ - start = time.time() - docs = self.get_all_documents() - refs = [x for x in docs if x.endswith('reference')] - others = [x for x in docs if not x.endswith('reference')] - - # Build the reference manual twice to resolve references. That is, - # build once with the inventory builder to construct the intersphinx - # inventory files, and then build the second time for real. So the - # first build should be as fast as possible; - logger.warning("\nBuilding reference manual, first pass.\n") - for document in refs: - getattr(get_builder(document), 'inventory')(*args, **kwds) - - from sage.env import SAGE_DOC - logger.warning("Building reference manual, second pass.\n") - os.makedirs(os.path.join(SAGE_DOC, "html", "en", "reference", "_static"), exist_ok=True) - for document in refs: - getattr(get_builder(document), name)(*args, **kwds) - - # build the other documents in parallel - L = [(doc, name, kwds) + args for doc in others] - - # Issue #31344: Work around crashes from multiprocessing - if sys.platform == 'darwin': - for target in L: - build_other_doc(target) - else: - build_many(build_other_doc, L) - logger.warning("Elapsed time: %.1f seconds." % (time.time() - start)) - logger.warning("Done building the documentation!") - - def get_all_documents(self): - """ - Return a list of all of the documents. - - A document is a directory within one of the language - subdirectories of SAGE_DOC_SRC specified by the global - LANGUAGES variable. - - EXAMPLES:: - - sage: from sage_docbuild.builders import AllBuilder - sage: documents = AllBuilder().get_all_documents() - sage: 'en/tutorial' in documents # optional - sage_spkg - True - sage: documents[0] == 'en/reference' - True - """ - documents = [] - for lang in build_options.LANGUAGES: - for document in os.listdir(os.path.join(SAGE_DOC_SRC, lang)): - if (document not in build_options.OMIT - and os.path.isdir(os.path.join(SAGE_DOC_SRC, lang, document))): - documents.append(os.path.join(lang, document)) - - # Ensure that the reference guide is compiled first so that links from - # the other documents to it are correctly resolved. - if 'en/reference' in documents: - documents.remove('en/reference') - documents.insert(0, 'en/reference') - - return documents - - class WebsiteBuilder(DocBuilder): def html(self): """ @@ -502,28 +410,22 @@ def clean(self): DocBuilder.clean(self) -class ReferenceBuilder(AllBuilder): +class ReferenceBuilder(): """ - This class builds the reference manual. It uses DocBuilder to + This class builds the reference manual. It uses DocBuilder to build the top-level page and ReferenceSubBuilder for each sub-component. """ - def __init__(self, name, lang='en'): + def __init__(self, name:str, options: BuildOptions, lang:str='en'): """ Record the reference manual's name, in case it's not identical to 'reference'. """ - AllBuilder.__init__(self) - doc = name.split(os.path.sep) - - if doc[0] in build_options.LANGUAGES: - lang = doc[0] - doc.pop(0) - - self.name = doc[0] + self.name = name self.lang = lang + self.options = options - def _output_dir(self, type, lang=None): + def _output_dir(self, type: Literal['html', 'latex', 'pdf']) -> Path: """ Return the directory where the output of type ``type`` is stored. @@ -537,15 +439,12 @@ def _output_dir(self, type, lang=None): sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/reference' """ - from sage.env import SAGE_DOC - if lang is None: - lang = self.lang - d = os.path.join(SAGE_DOC, type, lang, self.name) - os.makedirs(d, exist_ok=True) - return d + dir = self.options.output_dir / type / self.lang / self.name + dir.mkdir(exist_ok=True) + return dir - def _refdir(self): - return os.path.join(SAGE_DOC_SRC, self.lang, self.name) + def _source_dir(self) -> Path: + return self.options.source_dir / self.lang / self.name def _build_bibliography(self, format, *args, **kwds): """ @@ -554,9 +453,8 @@ def _build_bibliography(self, format, *args, **kwds): The bibliography references.aux is referenced by the other manuals and needs to be built first. """ - refdir = self._refdir() references = [ - (doc, self.lang, format, kwds) + args for doc in self.get_all_documents(refdir) + (doc, self.lang, format, kwds) + args for doc in get_all_documents(self._source_dir()) if doc == 'reference/references' ] build_many(build_ref_doc, references) @@ -565,10 +463,9 @@ def _build_everything_except_bibliography(self, format, *args, **kwds): """ Build the entire reference manual except the bibliography """ - refdir = self._refdir() non_references = [ - (doc, self.lang, format, kwds) + args for doc in self.get_all_documents(refdir) - if doc != 'reference/references' + (doc, self.lang, format, kwds) + args for doc in get_all_documents(self._source_dir()) + if doc != Path('reference/references') ] build_many(build_ref_doc, non_references) @@ -576,18 +473,17 @@ def _build_top_level(self, format, *args, **kwds): """ Build top-level document. """ - getattr(ReferenceTopBuilder('reference'), format)(*args, **kwds) + getattr(ReferenceTopBuilder('reference', self.options), format)(*args, **kwds) def _wrapper(self, format, *args, **kwds): """ - Build reference manuals: build the - top-level document and its components. + Build reference manuals: build the top-level document and its components. """ logger.info('Building bibliography') self._build_bibliography(format, *args, **kwds) logger.info('Bibliography finished, building dependent manuals') self._build_everything_except_bibliography(format, *args, **kwds) - # The html refman must be build at the end to ensure correct + # The html refman must be built at the end to ensure correct # merging of indexes and inventories. # Sphinx is run here in the current process (not in a # subprocess) and the IntersphinxCache gets populated to be @@ -595,46 +491,15 @@ def _wrapper(self, format, *args, **kwds): # the other documents. self._build_top_level(format, *args, **kwds) - def get_all_documents(self, refdir): - """ - Return a list of all reference manual components to build. - - We add a component name if it's a subdirectory of the manual's - directory and contains a file named 'index.rst'. - - We return the largest component (most subdirectory entries) - first since they will take the longest to build. - - EXAMPLES:: - - sage: from sage_docbuild.builders import ReferenceBuilder - sage: b = ReferenceBuilder('reference') - sage: refdir = os.path.join(os.environ['SAGE_DOC_SRC'], 'en', b.name) # optional - sage_spkg - sage: sorted(b.get_all_documents(refdir)) # optional - sage_spkg - ['reference/algebras', - 'reference/arithgroup', - ..., - 'reference/valuations'] - """ - documents = [] - - for doc in os.listdir(refdir): - directory = os.path.join(refdir, doc) - if os.path.exists(os.path.join(directory, 'index.rst')): - n = len(os.listdir(directory)) - documents.append((-n, os.path.join(self.name, doc))) - - return [doc[1] for doc in sorted(documents)] - - class ReferenceTopBuilder(DocBuilder): """ This class builds the top-level page of the reference manual. """ - def __init__(self, *args, **kwds): - DocBuilder.__init__(self, *args, **kwds) + def __init__(self, name: str, options: BuildOptions, lang: str='en'): + DocBuilder.__init__(self, name, options, lang) self.name = 'reference' self.lang = 'en' + self.options = options def _output_dir(self, type, lang=None): """ @@ -700,7 +565,7 @@ def html(self): # For the content, we modify doc/en/reference/index.rst, which # has two parts: the body and the table of contents. - with open(os.path.join(SAGE_DOC_SRC, self.lang, 'reference', 'index.rst')) as f: + with open(self.options.source_dir / self.lang / 'reference' / 'index.rst') as f: rst = f.read() # Get rid of todolist and miscellaneous rst markup. rst = rst.replace('.. _reference-manual:\n\n', '') @@ -762,15 +627,15 @@ class ReferenceSubBuilder(DocBuilder): When building any output, we must first go through and check to see if we need to update any of the autogenerated reST - files. There are two cases where this would happen: + files. There are two cases where this would happen: 1. A new module gets added to one of the toctrees. - - 2. The actual module gets updated and possibly contains a new - title. + 2. The actual module gets updated and possibly contains a new title. """ - def __init__(self, *args, **kwds): - DocBuilder.__init__(self, *args, **kwds) + _cache = None + + def __init__(self, name: str, options: BuildOptions, lang: str='en'): + DocBuilder.__init__(self, name, options, lang) self._wrap_builder_helpers() def _wrap_builder_helpers(self): @@ -802,8 +667,7 @@ def _wrapper(self, build_type, *args, **kwds): cache['option_underscore'] = self._options.underscore self.save_cache() - # After "sage -clone", refresh the reST file mtimes in - # environment.pickle. + # Refresh the reST file mtimes in environment.pickle if self._options.update_mtimes: logger.info("Checking for reST file mtimes to update...") self.update_mtimes() @@ -819,40 +683,43 @@ def _wrapper(self, build_type, *args, **kwds): self.write_auto_rest_file(module_name) # Copy over the custom reST files from _sage - _sage = os.path.join(self.dir, '_sage') - if os.path.exists(_sage): - logger.info("Copying over custom reST files from %s ...", _sage) - shutil.copytree(_sage, os.path.join(self.dir, 'sage')) + _sage = self.dir / '_sage' + if _sage.exists(): + logger.info(f"Copying over custom reST files from {_sage} ...") + shutil.copytree(_sage, self.dir / 'sage') getattr(DocBuilder, build_type)(self, *args, **kwds) - def cache_filename(self): + def cache_file(self) -> Path: """ Return the filename where the pickle of the reference cache is stored. """ - return os.path.join(self._doctrees_dir(), 'reference.pickle') + return self._doctrees_dir() / 'reference.pickle' - @cached_method def get_cache(self): """ Retrieve the reference cache which contains the options previously used by the reference builder. - If it doesn't exist, then we just return an empty dictionary. If it + If it doesn't exist, then we just return an empty dictionary. If it is corrupted, return an empty dictionary. """ - filename = self.cache_filename() - if not os.path.exists(filename): + if self._cache is not None: + return self._cache + + cache_file = self.cache_file() + if not cache_file.exists(): return {} - with open(self.cache_filename(), 'rb') as file: - try: + try: + with cache_file.open('rb') as file: cache = pickle.load(file) - except Exception: - logger.debug("Cache file '%s' is corrupted; ignoring it..." % filename) - cache = {} - else: - logger.debug("Loaded the reference cache: %s", filename) + except Exception: + logger.debug(f"Cache file '{cache_file}' is corrupted; ignoring it...") + cache = {} + else: + logger.debug(f"Loaded the reference cache: {cache_file}") + self._cache = cache return cache def save_cache(self): @@ -861,11 +728,11 @@ def save_cache(self): """ cache = self.get_cache() try: - with open(self.cache_filename(), 'wb') as file: + with open(self.cache_file(), 'wb') as file: pickle.dump(cache, file) - logger.debug("Saved the reference cache: %s", self.cache_filename()) + logger.debug("Saved the reference cache: %s", self.cache_file()) except PermissionError: - logger.debug("Permission denied for the reference cache: %s", self.cache_filename()) + logger.debug("Permission denied for the reference cache: %s", self.cache_file()) def get_sphinx_environment(self): """ @@ -877,7 +744,7 @@ def get_sphinx_environment(self): env = pickle.load(f) logger.debug("Opened Sphinx environment: %s", env_pickle) return env - except (OSError, EOFError) as err: + except (OSError, EOFError): logger.debug( f"Failed to open Sphinx environment '{env_pickle}'", exc_info=True) @@ -934,26 +801,22 @@ def print_modified_modules(self): for module_name in self.get_modified_modules(): print(module_name) - def get_all_rst_files(self, exclude_sage=True): + def get_all_rst_files(self) -> Generator[Path, None, None]: """ - Return an iterator for all rst files which are not - autogenerated. + Return an iterator for all rst files which are not autogenerated. """ - for directory, subdirs, files in os.walk(self.dir): - if exclude_sage and directory.startswith(os.path.join(self.dir, 'sage')): + for file in self.dir.rglob('*.rst'): + if 'sage' in file.relative_to(self.dir).parts: continue - for filename in files: - if not filename.endswith('.rst'): - continue - yield os.path.join(directory, filename) + yield file def get_all_included_modules(self): """ Return an iterator for all modules which are included in the reference manual. """ - for filename in self.get_all_rst_files(): - for module in self.get_modules(filename): + for file in self.get_all_rst_files(): + for module in self.get_modules(file): yield module def get_new_and_updated_modules(self): @@ -1030,9 +893,9 @@ def print_new_and_updated_modules(self): for module_name in self.get_new_and_updated_modules(): print(module_name) - def get_modules(self, filename): + def get_modules(self, file: Path) -> Generator[str, None, None]: """ - Given a filename for a reST file, return an iterator for + Given a reST file, return an iterator for all of the autogenerated reST files that it includes. """ from sage.features.all import all_features @@ -1041,10 +904,11 @@ def get_modules(self, filename): auto_re = re.compile(r'^\s*(..\/)*(sage(_docbuild)?\/[\w\/]*)\s*$') # Read the lines - with open(filename) as f: + with file.open(encoding='utf-8') as f: lines = f.readlines() skip = False + indent = 0 for line in lines: if skip: if not line.strip() or line.count(' ', 0) >= indent: @@ -1064,7 +928,7 @@ def get_modules(self, filename): pass match = auto_re.match(line) if match: - yield match.group(2).replace(os.path.sep, '.') + yield match.group(2).replace('/', '.') def get_module_docstring_title(self, module_name): """ @@ -1090,7 +954,7 @@ def get_module_docstring_title(self, module_name): else: return doc - def auto_rest_filename(self, module_name): + def auto_rest_filename(self, module_name: str) -> Path: """ Return the name of the file associated to a given module @@ -1100,9 +964,9 @@ def auto_rest_filename(self, module_name): sage: ReferenceSubBuilder("reference").auto_rest_filename("sage.combinat.partition") '.../en/reference/sage/combinat/partition.rst' """ - return self.dir + os.path.sep + module_name.replace('.', os.path.sep) + '.rst' + return self.dir / (module_name.replace('.', os.path.sep) + '.rst') - def write_auto_rest_file(self, module_name): + def write_auto_rest_file(self, module_name: str): """ Write the autogenerated reST file for module_name. """ @@ -1318,45 +1182,96 @@ def _doctrees_dir(self): return self._output_dir('doctrees') -def get_builder(name): +def get_builder(name: str, options: BuildOptions) -> DocBuilder | ReferenceBuilder: """ Return an appropriate *Builder* object for the document ``name``. DocBuilder and its subclasses do all the real work in building the documentation. """ - if name == 'all': - from sage.misc.superseded import deprecation - deprecation(31948, 'avoid using "sage --docbuild all html" and "sage --docbuild all pdf"; ' - 'use "make doc" and "make doc-pdf" instead, if available.') - return AllBuilder() - elif name == 'reference_top': - return ReferenceTopBuilder('reference') + if name == 'reference_top': + return ReferenceTopBuilder('reference', options) elif name.endswith('reference'): return ReferenceBuilder(name) - elif 'reference' in name and os.path.exists(os.path.join(SAGE_DOC_SRC, 'en', name)): - return ReferenceSubBuilder(name) + elif 'reference' in name and (options.source_dir / 'en' / name).exists(): + return ReferenceSubBuilder(name, options) elif name.endswith('website'): - return WebsiteBuilder(name) + return WebsiteBuilder(name, options) elif name.startswith('file='): path = name[5:] if path.endswith('.sage') or path.endswith('.pyx'): raise NotImplementedError('Building documentation for a single file only works for Python files.') return SingleFileBuilder(path) - elif name in get_documents() or name in AllBuilder().get_all_documents(): - return DocBuilder(name) + elif name in get_documents() or name in get_all_documents(options): + return DocBuilder(name, options) else: print("'%s' is not a recognized document. Type 'sage --docbuild -D' for a list" % name) print("of documents, or 'sage --docbuild --help' for more help.") sys.exit(1) -def get_documents(): +def get_all_documents(source: Path) -> list[Path]: + """ + Return a list of all of the documents, relative to the source + directory. + + A document is a directory within one of the language + subdirectories of ``doc``. + + EXAMPLES:: + + sage: from sage_docbuild.builders import get_all_documents + sage: documents = get_all_documents() + sage: 'en/tutorial' in documents # optional - sage_spkg + True + sage: documents[0] == 'en/reference' + True + """ + documents = [] + for lang in [path for path in source.iterdir() if path.is_dir()]: + for document in lang.iterdir(): + if (document.name not in build_options.OMIT + and document.is_dir()): + documents.append(document.relative_to(source)) + + # Ensure that the reference guide is compiled first so that links from + # the other documents to it are correctly resolved. + if Path('en/reference') in documents: + documents.remove(Path('en/reference')) + documents.insert(0, Path('en/reference')) + + return documents + +def get_all_reference_documents(source: Path) -> list[Path]: """ - Return a list of document names the Sage documentation builder - will accept as command-line arguments. + Return a list of all reference manual documents to build, relative to the + specified source directory. + + We add a document if it's a subdirectory of the manual's + directory and contains a file named 'index.rst'. + + The order corresponds to the order in which the documents should be built. + + EXAMPLES:: + + sage: refdir = Path(os.environ['SAGE_DOC_SRC']) / 'en' # optional - sage_spkg + sage: sorted(get_all_reference_documents(refdir)) # optional - sage_spkg + ['reference/algebras', + 'reference/arithgroup', + ..., + 'reference/valuations'] """ - all_b = AllBuilder() - docs = all_b.get_all_documents() - docs = [(d[3:] if d[0:3] == 'en/' else d) for d in docs] + documents: list[tuple[int, Path]] = [] + + for directory in (source / 'reference').iterdir(): + if (directory / 'index.rst').exists(): + n = len(list(directory.iterdir())) + documents.append((-n, directory.relative_to(source))) + + # Sort largest component (most subdirectory entries) first since + # they will take the longest to build + docs = [doc[1] for doc in sorted(documents)] + # Put the bibliography first, because it needs to be built first: + docs.remove(Path('reference/references')) + docs.insert(0, Path('reference/references')) return docs From d7c3b6e1ea8fa4b5794136f5c4e151a8196fc0bf Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 20 Apr 2025 16:09:55 +0000 Subject: [PATCH 02/21] Fix meson doc build --- meson.build | 3 + src/doc/bootstrap | 1 + src/doc/en/reference/repl/meson.build | 10 +++ src/doc/meson.build | 56 ++++++-------- src/sage_docbuild/__main__.py | 10 ++- src/sage_docbuild/builders.py | 101 +++++++++----------------- src/sage_docbuild/conf.py | 1 + 7 files changed, 78 insertions(+), 104 deletions(-) create mode 100644 src/doc/en/reference/repl/meson.build diff --git a/meson.build b/meson.build index ac5594852ff..e2f7fa3d094 100644 --- a/meson.build +++ b/meson.build @@ -4,6 +4,7 @@ project( version: files('src/VERSION.txt'), license: 'GPL v3', default_options: ['c_std=c17', 'cpp_std=c++17'], + meson_version: '>=1.2', ) # Python module @@ -212,4 +213,6 @@ for path in file_paths: ] run_command(create_files_command, check: true) +root = meson.current_source_dir() + subdir('src') diff --git a/src/doc/bootstrap b/src/doc/bootstrap index e99ecd52c28..9d59aa1755e 100755 --- a/src/doc/bootstrap +++ b/src/doc/bootstrap @@ -18,6 +18,7 @@ if [ -z "$SAGE_ROOT" ]; then fi cd "$SAGE_ROOT" +export PATH=build/bin:$PATH OUTPUT_DIR="src/doc/en/installation" mkdir -p "$OUTPUT_DIR" diff --git a/src/doc/en/reference/repl/meson.build b/src/doc/en/reference/repl/meson.build new file mode 100644 index 00000000000..ea6298ec3ee --- /dev/null +++ b/src/doc/en/reference/repl/meson.build @@ -0,0 +1,10 @@ +doc_src += custom_target( + 'doc-src', + output: ['options.txt'], + command: [ + py, + src / 'sage' / 'cli', + '--help' + ], + capture: true, +) diff --git a/src/doc/meson.build b/src/doc/meson.build index d6be7b7122d..e28434e299f 100644 --- a/src/doc/meson.build +++ b/src/doc/meson.build @@ -1,32 +1,16 @@ -# Clean target -# clean = custom_target( -# 'clean', -# output: [], -# command: [ -# 'sh', '-c', -# ''' -# rm -rf en/reference/*/sage -# rm -rf en/reference/documentation/sage_docbuild -# rm -rf en/reference/sage -# rm -f common/*.pyc -# ''' -# ] -# ) - -# Generate sources at build time -# doc_src = custom_target( -# 'doc-src', -# output: ['en/reference/repl/options.txt'], -# command: [ -# 'sh', '-c', -# ''' -# mkdir -p en/reference/repl -# sage -advanced > en/reference/repl/options.txt -# ''' -# ] -# ) - - +doc_src = [] +subdir('en/reference/repl') +# TODO: Migrate this completely to meson +doc_src += custom_target( + 'doc-src', + output: ['autogen'], + command: [ + files('bootstrap'), + ], + env: { + 'SAGE_ROOT': root, + }, +) references = run_command( py, @@ -45,8 +29,12 @@ reference_pdf = [] bibliography = [] foreach type : ['inventory', 'html', 'pdf'] foreach ref : references.splitlines() - short_ref = ref.split('/')[1] - deps = [] + if '/' in ref + short_ref = ref.split('/')[1] + else + short_ref = ref + endif + deps = [doc_src] if type == 'html' or type == 'pdf' deps += reference_inventory endif @@ -99,17 +87,17 @@ foreach type : ['html', 'pdf'] 'doc-' + type + '-other-' + short_doc, output: [type + short_doc], command: [ - py, + py, src / 'build-docs.py', '--no-pdf-links', doc, - type, + type, '-o', '@OUTDIR@', '--source', meson.current_source_dir() ], depends: reference_inventory, ) - if type == 'html' + if type == 'html' other_documents_html += target elif type == 'pdf' other_documents_pdf += target diff --git a/src/sage_docbuild/__main__.py b/src/sage_docbuild/__main__.py index 6a180efc921..3b7d74548f6 100644 --- a/src/sage_docbuild/__main__.py +++ b/src/sage_docbuild/__main__.py @@ -498,13 +498,11 @@ def excepthook(*exc_info): sys.excepthook = excepthook - # Process selected options. + # Set up the environment based on the command-line options if args.check_nested: os.environ['SAGE_CHECK_NESTED'] = 'True' - if args.underscore: os.environ['SAGE_DOC_UNDERSCORE'] = "True" - if args.sphinx_opts: build_options.ALLSPHINXOPTS += args.sphinx_opts.replace(',', ' ') + " " if args.no_pdf_links: @@ -521,6 +519,8 @@ def excepthook(*exc_info): os.environ['SAGE_SKIP_TESTS_BLOCKS'] = 'True' if args.use_cdns: os.environ['SAGE_USE_CDNS'] = 'yes' + os.environ['SAGE_DOC_SRC'] = str(args.source_dir.absolute()) + os.environ['SAGE_DOC'] = str(args.output_dir.absolute()) build_options.ABORT_ON_ERROR = not args.keep_going @@ -535,11 +535,13 @@ def excepthook(*exc_info): # directories it leaves behind. See Issue #20010. # Issue #31948: This is not parallelization-safe; use the option # --no-prune-empty-dirs to turn it off - for dirpath, dirnames, filenames in os.walk(builder.dir, topdown=False): + for dirpath, dirnames, filenames in os.walk(args.source_dir, topdown=False): if not dirnames + filenames: logger.warning('Deleting empty directory {0}'.format(dirpath)) os.rmdir(dirpath) + import sage.all # TODO: Remove once all modules can be imported independently # noqa: F401 + build = getattr(builder, typ) build() diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index ef3af17db87..ba893a7fcbb 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -179,18 +179,15 @@ def f(self, *args, **kwds): class DocBuilder(): - def __init__(self, name: str, options: BuildOptions, lang: str='en'): + def __init__(self, name: str, options: BuildOptions): """ INPUT: - ``name`` -- the name of a subdirectory in ``doc/``, such as 'tutorial' or 'installation' - - - ``lang`` -- (default "en") the language of the document. """ self.name = name - self.lang = lang - self.dir = options.source_dir / self.lang / self.name + self.dir = options.source_dir / self.name self._options = options def _output_dir(self, type): @@ -203,11 +200,11 @@ def _output_dir(self, type): EXAMPLES:: sage: from sage_docbuild.builders import DocBuilder - sage: b = DocBuilder('tutorial') + sage: b = DocBuilder('en/tutorial') sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/tutorial' """ - dir = self._options.output_dir / type / self.lang / self.name + dir = self._options.output_dir / type / self.name dir.mkdir(parents=True, exist_ok=True) return dir @@ -225,7 +222,7 @@ def _doctrees_dir(self) -> Path: sage: b._doctrees_dir() # optional - sagemath_doc_html '.../doctrees/en/tutorial' """ - dir = self._options.output_dir / 'doctrees' / self.lang / self.name + dir = self._options.output_dir / 'doctrees' / self.name dir.mkdir(parents=True, exist_ok=True) return dir @@ -324,16 +321,6 @@ def build_many(target, args, processes=None): ########################################## # Parallel Building Ref Manual # ########################################## - -def build_other_doc(args): - document = args[0] - name = args[1] - kwds = args[2] - args = args[3:] - logger.warning("\nBuilding %s.\n" % document) - getattr(get_builder(document), name)(*args, **kwds) - - class WebsiteBuilder(DocBuilder): def html(self): """ @@ -416,13 +403,12 @@ class ReferenceBuilder(): build the top-level page and ReferenceSubBuilder for each sub-component. """ - def __init__(self, name:str, options: BuildOptions, lang:str='en'): + def __init__(self, name:str, options: BuildOptions): """ Record the reference manual's name, in case it's not identical to 'reference'. """ self.name = name - self.lang = lang self.options = options def _output_dir(self, type: Literal['html', 'latex', 'pdf']) -> Path: @@ -439,12 +425,12 @@ def _output_dir(self, type: Literal['html', 'latex', 'pdf']) -> Path: sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/reference' """ - dir = self.options.output_dir / type / self.lang / self.name + dir = self.options.output_dir / type / self.name dir.mkdir(exist_ok=True) return dir def _source_dir(self) -> Path: - return self.options.source_dir / self.lang / self.name + return self.options.source_dir / self.name def _build_bibliography(self, format, *args, **kwds): """ @@ -454,7 +440,7 @@ def _build_bibliography(self, format, *args, **kwds): manuals and needs to be built first. """ references = [ - (doc, self.lang, format, kwds) + args for doc in get_all_documents(self._source_dir()) + (doc, 'en', format, kwds) + args for doc in get_all_documents(self._source_dir()) if doc == 'reference/references' ] build_many(build_ref_doc, references) @@ -464,7 +450,7 @@ def _build_everything_except_bibliography(self, format, *args, **kwds): Build the entire reference manual except the bibliography """ non_references = [ - (doc, self.lang, format, kwds) + args for doc in get_all_documents(self._source_dir()) + (doc, 'en', format, kwds) + args for doc in get_all_documents(self._source_dir()) if doc != Path('reference/references') ] build_many(build_ref_doc, non_references) @@ -495,32 +481,8 @@ class ReferenceTopBuilder(DocBuilder): """ This class builds the top-level page of the reference manual. """ - def __init__(self, name: str, options: BuildOptions, lang: str='en'): - DocBuilder.__init__(self, name, options, lang) - self.name = 'reference' - self.lang = 'en' - self.options = options - - def _output_dir(self, type, lang=None): - """ - Return the directory where the output of type ``type`` is stored. - - If the directory does not exist, then it will automatically be - created. - - EXAMPLES:: - - sage: from sage_docbuild.builders import ReferenceTopBuilder - sage: b = ReferenceTopBuilder('reference') - sage: b._output_dir('html') # optional - sagemath_doc_html - '.../html/en/reference' - """ - from sage.env import SAGE_DOC - if lang is None: - lang = self.lang - d = os.path.join(SAGE_DOC, type, lang, self.name) - os.makedirs(d, exist_ok=True) - return d + def __init__(self, name: str, options: BuildOptions): + DocBuilder.__init__(self, 'en/reference', options) def html(self): """ @@ -531,14 +493,9 @@ def html(self): # We want to build master index file which lists all of the PDF file. # We modify the file index.html from the "reference_top" target, if it # exists. Otherwise, we are done. - - from sage.env import SAGE_DOC - reference_dir = os.path.join(SAGE_DOC, 'html', 'en', 'reference') + reference_dir = self.dir output_dir = self._output_dir('html') - with open(os.path.join(reference_dir, 'index.html')) as f: - html = f.read() - # Install in output_dir a symlink to the directory containing static files. # Prefer relative path for symlinks. relpath = os.path.relpath(reference_dir, output_dir) @@ -548,8 +505,8 @@ def html(self): pass # Now modify top reference index.html page and write it to output_dir. - html_output_dir = os.path.dirname(reference_dir) - + with open(reference_dir / 'index.html') as f: + html = f.read() # Fix links in navigation bar html = re.sub(r'Sage(.*)Documentation', r'Sage\2Documentation', @@ -565,7 +522,7 @@ def html(self): # For the content, we modify doc/en/reference/index.rst, which # has two parts: the body and the table of contents. - with open(self.options.source_dir / self.lang / 'reference' / 'index.rst') as f: + with open(reference_dir / 'index.rst') as f: rst = f.read() # Get rid of todolist and miscellaneous rst markup. rst = rst.replace('.. _reference-manual:\n\n', '') @@ -634,8 +591,8 @@ class ReferenceSubBuilder(DocBuilder): """ _cache = None - def __init__(self, name: str, options: BuildOptions, lang: str='en'): - DocBuilder.__init__(self, name, options, lang) + def __init__(self, name: str, options: BuildOptions): + DocBuilder.__init__(self, "en/" + name, options) self._wrap_builder_helpers() def _wrap_builder_helpers(self): @@ -688,6 +645,13 @@ def _wrapper(self, build_type, *args, **kwds): logger.info(f"Copying over custom reST files from {_sage} ...") shutil.copytree(_sage, self.dir / 'sage') + # Copy over some generated reST file in the build directory + # (Background: Meson puts them in the build directory, but Sphinx can also read + # files from the source directory, see https://github.com/sphinx-doc/sphinx/issues/3132) + generated_dir = self._options.output_dir / self.name + for file in generated_dir.rglob('*'): + shutil.copy2(file, self.dir / file.relative_to(generated_dir)) + getattr(DocBuilder, build_type)(self, *args, **kwds) def cache_file(self) -> Path: @@ -1192,7 +1156,7 @@ def get_builder(name: str, options: BuildOptions) -> DocBuilder | ReferenceBuild if name == 'reference_top': return ReferenceTopBuilder('reference', options) elif name.endswith('reference'): - return ReferenceBuilder(name) + return ReferenceBuilder(name, options) elif 'reference' in name and (options.source_dir / 'en' / name).exists(): return ReferenceSubBuilder(name, options) elif name.endswith('website'): @@ -1202,7 +1166,7 @@ def get_builder(name: str, options: BuildOptions) -> DocBuilder | ReferenceBuild if path.endswith('.sage') or path.endswith('.pyx'): raise NotImplementedError('Building documentation for a single file only works for Python files.') return SingleFileBuilder(path) - elif name in get_documents() or name in get_all_documents(options): + elif Path(name) in get_all_documents(options.source_dir): return DocBuilder(name, options) else: print("'%s' is not a recognized document. Type 'sage --docbuild -D' for a list" % name) @@ -1229,16 +1193,17 @@ def get_all_documents(source: Path) -> list[Path]: """ documents = [] for lang in [path for path in source.iterdir() if path.is_dir()]: + if not re.match('^[a-z][a-z]$', lang.name): + # Skip non-language directories + continue for document in lang.iterdir(): if (document.name not in build_options.OMIT and document.is_dir()): documents.append(document.relative_to(source)) - # Ensure that the reference guide is compiled first so that links from - # the other documents to it are correctly resolved. + # Top-level reference document is build seperately if Path('en/reference') in documents: documents.remove(Path('en/reference')) - documents.insert(0, Path('en/reference')) return documents @@ -1274,4 +1239,8 @@ def get_all_reference_documents(source: Path) -> list[Path]: # Put the bibliography first, because it needs to be built first: docs.remove(Path('reference/references')) docs.insert(0, Path('reference/references')) + + # Add the top-level reference document + docs.append(Path('reference_top')) + return docs diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 2b1cbd138ae..5ee1bbd2708 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -1093,6 +1093,7 @@ def setup(app): # When building the standard docs, app.srcdir is set to SAGE_DOC_SRC + # 'LANGUAGE/DOCNAME'. if app.srcdir.is_relative_to(SAGE_DOC_SRC): + app.add_config_value('intersphinx_resolve_self', 'sagemath', False) app.add_config_value('intersphinx_mapping', {}, False) app.add_config_value('intersphinx_cache_limit', 5, False) app.add_config_value('intersphinx_disabled_reftypes', [], False) From a805a9775165e5dc585455142b9136c384016fb5 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 02:41:30 +0000 Subject: [PATCH 03/21] Fix various issues --- .github/workflows/doc-build.yml | 2 +- src/doc/Makefile | 8 +- src/doc/en/reference/repl/meson.build | 12 +-- src/doc/meson.build | 142 +++++++++++++------------- src/sage_docbuild/builders.py | 11 +- 5 files changed, 86 insertions(+), 89 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 63c77b67ae2..9006409b9cd 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -76,7 +76,7 @@ jobs: - name: Get workflow run-id id: get_run_id - if: steps.container.outcome == 'success' && !startsWith(github.ref, 'refs/tags/') && github.event_name == 'pull_request' + if: !startsWith(github.ref, 'refs/tags/') && github.event_name == 'pull_request' run: | RESPONSE=$(curl -s -L \ -H "Accept: application/vnd.github+json" \ diff --git a/src/doc/Makefile b/src/doc/Makefile index 9c03292b070..395a70de68b 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -51,7 +51,7 @@ doc-html-reference-sub: doc-inventory-reference $(eval DOCS = $(shell sage --docbuild --all-documents reference)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi $(eval BIBLIO = $(firstword $(DOCS))) - $(eval OTHER_DOCS = $(wordlist 2, 100, $(DOCS))) + $(eval OTHER_DOCS = $(filter-out reference_top, $(wordlist 2, 100, $(DOCS)))) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-html--$(subst /,-,$(BIBLIO)) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(OTHER_DOCS), doc-html--$(subst /,-,$(doc))) @@ -63,7 +63,7 @@ doc-html-reference: doc-html-reference-sub doc-html-other: doc-html-reference $(eval DOCS = $(shell sage --docbuild --all-documents all)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi - $(MAKE) $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-html--$(subst /,-,$(doc))) + $(MAKE) $(foreach doc, $(DOCS), doc-html--$(subst /,-,$(doc))) doc-html: doc-html-reference doc-html-other SAGE_DOC=$$(sage --python -c "from sage.env import SAGE_DOC; print(SAGE_DOC)") @@ -78,7 +78,7 @@ doc-pdf-reference: doc-inventory-reference $(eval DOCS = $(shell sage --docbuild --all-documents reference)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi $(eval BIBLIO = $(firstword $(DOCS))) - $(eval OTHER_DOCS = $(wordlist 2, 100, $(DOCS))) + $(eval OTHER_DOCS = $(filter-out reference_top, $(wordlist 2, 100, $(DOCS)))) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-pdf--$(subst /,-,$(BIBLIO)) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(OTHER_DOCS), doc-pdf--$(subst /,-,$(doc))) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-pdf--reference_top @@ -87,7 +87,7 @@ doc-pdf-reference: doc-inventory-reference doc-pdf-other: doc-pdf-reference $(eval DOCS = $(shell sage --docbuild --all-documents all)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi - $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-pdf--$(subst /,-,$(doc))) + $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(DOCS), doc-pdf--$(subst /,-,$(doc))) doc-pdf: doc-pdf-reference doc-pdf-other SAGE_DOC=$$(sage --python -c "from sage.env import SAGE_DOC; print(SAGE_DOC)") diff --git a/src/doc/en/reference/repl/meson.build b/src/doc/en/reference/repl/meson.build index ea6298ec3ee..381f31d0f00 100644 --- a/src/doc/en/reference/repl/meson.build +++ b/src/doc/en/reference/repl/meson.build @@ -1,10 +1,6 @@ doc_src += custom_target( - 'doc-src', - output: ['options.txt'], - command: [ - py, - src / 'sage' / 'cli', - '--help' - ], - capture: true, + 'doc-src', + output: ['options.txt'], + command: [py, src / 'sage' / 'cli', '--help'], + capture: true, ) diff --git a/src/doc/meson.build b/src/doc/meson.build index e28434e299f..3a8922456f8 100644 --- a/src/doc/meson.build +++ b/src/doc/meson.build @@ -2,14 +2,10 @@ doc_src = [] subdir('en/reference/repl') # TODO: Migrate this completely to meson doc_src += custom_target( - 'doc-src', - output: ['autogen'], - command: [ - files('bootstrap'), - ], - env: { - 'SAGE_ROOT': root, - }, + 'doc-src', + output: ['autogen'], + command: [files('bootstrap')], + env: {'SAGE_ROOT': root}, ) references = run_command( @@ -18,7 +14,8 @@ references = run_command( src / 'build-docs.py', '--all-documents', 'reference', - '--source', meson.current_source_dir() + '--source', + meson.current_source_dir(), ], check: true, ).stdout().strip() @@ -28,44 +25,46 @@ reference_html = [] reference_pdf = [] bibliography = [] foreach type : ['inventory', 'html', 'pdf'] - foreach ref : references.splitlines() - if '/' in ref - short_ref = ref.split('/')[1] - else - short_ref = ref - endif - deps = [doc_src] - if type == 'html' or type == 'pdf' - deps += reference_inventory - endif - if short_ref != 'references' - deps += bibliography - endif - target = custom_target( - 'doc-' + type + '-reference-' + short_ref, - output: [type + short_ref], - command: [ - py, - src / 'build-docs.py', - '--no-pdf-links', - ref, - type, - '-o', '@OUTDIR@', - '--source', meson.current_source_dir() - ], - depends: deps, - ) - if short_ref == 'references' - bibliography += target - endif - if type == 'inventory' - reference_inventory += target - elif type == 'html' - reference_html += target - elif type == 'pdf' - reference_pdf += target - endif - endforeach + foreach ref : references.splitlines() + if '/' in ref + short_ref = ref.split('/')[1] + else + short_ref = ref + endif + deps = [doc_src] + if type == 'html' or type == 'pdf' + deps += reference_inventory + endif + if short_ref != 'references' + deps += bibliography + endif + target = custom_target( + 'doc-' + type + '-reference-' + short_ref, + output: [type + short_ref], + command: [ + py, + src / 'build-docs.py', + '--no-pdf-links', + ref, + type, + '-o', + '@OUTDIR@', + '--source', + meson.current_source_dir(), + ], + depends: deps, + ) + if short_ref == 'references' + bibliography += target + endif + if type == 'inventory' + reference_inventory += target + elif type == 'html' + reference_html += target + elif type == 'pdf' + reference_pdf += target + endif + endforeach endforeach other_documents = run_command( @@ -74,35 +73,38 @@ other_documents = run_command( src / 'build-docs.py', '--all-documents', 'all', - '--source', meson.current_source_dir() + '--source', + meson.current_source_dir(), ], check: true, ).stdout().strip() other_documents_html = [] other_documents_pdf = [] foreach type : ['html', 'pdf'] - foreach doc : other_documents.splitlines() - short_doc = doc.replace('/', '-') - target = custom_target( - 'doc-' + type + '-other-' + short_doc, - output: [type + short_doc], - command: [ - py, - src / 'build-docs.py', - '--no-pdf-links', - doc, - type, - '-o', '@OUTDIR@', - '--source', meson.current_source_dir() - ], - depends: reference_inventory, - ) - if type == 'html' - other_documents_html += target - elif type == 'pdf' - other_documents_pdf += target - endif - endforeach + foreach doc : other_documents.splitlines() + short_doc = doc.replace('/', '-') + target = custom_target( + 'doc-' + type + '-other-' + short_doc, + output: [type + short_doc], + command: [ + py, + src / 'build-docs.py', + '--no-pdf-links', + doc, + type, + '-o', + '@OUTDIR@', + '--source', + meson.current_source_dir(), + ], + depends: reference_inventory, + ) + if type == 'html' + other_documents_html += target + elif type == 'pdf' + other_documents_pdf += target + endif + endforeach endforeach # Custom target for building the complete documentation diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index ba893a7fcbb..99a81e7b851 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -493,19 +493,18 @@ def html(self): # We want to build master index file which lists all of the PDF file. # We modify the file index.html from the "reference_top" target, if it # exists. Otherwise, we are done. - reference_dir = self.dir output_dir = self._output_dir('html') # Install in output_dir a symlink to the directory containing static files. # Prefer relative path for symlinks. - relpath = os.path.relpath(reference_dir, output_dir) + relpath = output_dir.relative_to(self._options.output_dir) try: - os.symlink(os.path.join(relpath, '_static'), os.path.join(output_dir, '_static')) + (output_dir / '_static').symlink_to(relpath / '_static') except FileExistsError: pass # Now modify top reference index.html page and write it to output_dir. - with open(reference_dir / 'index.html') as f: + with open(output_dir / 'index.html') as f: html = f.read() # Fix links in navigation bar html = re.sub(r'Sage(.*)Documentation', @@ -522,7 +521,7 @@ def html(self): # For the content, we modify doc/en/reference/index.rst, which # has two parts: the body and the table of contents. - with open(reference_dir / 'index.rst') as f: + with open(self.dir / 'index.rst') as f: rst = f.read() # Get rid of todolist and miscellaneous rst markup. rst = rst.replace('.. _reference-manual:\n\n', '') @@ -566,7 +565,7 @@ def html(self): rst_toc = re.sub(r'\n([A-Z][a-zA-Z, ]*)\n[-]*\n', r'\n\n\n

\1

\n\n
    \n', rst_toc) # now write the file. - with open(os.path.join(output_dir, 'index-pdf.html'), 'w') as new_index: + with open(output_dir / 'index-pdf.html', 'w') as new_index: new_index.write(html[:html_end_preamble]) new_index.write('

    Sage Reference Manual

    ') new_index.write(rst_body) From e881cf12626ef02fbeded0a6dd6b1fbcdbe4e0f6 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 02:47:15 +0000 Subject: [PATCH 04/21] Fix ci --- .github/workflows/doc-build.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 9006409b9cd..37c48ea8a95 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -71,12 +71,11 @@ jobs: pip install --no-build-isolation --config-settings=builddir=builddir . -v # - # On pull request and push to develop events + # For pull requests # - - name: Get workflow run-id id: get_run_id - if: !startsWith(github.ref, 'refs/tags/') && github.event_name == 'pull_request' + if: github.event_name == 'pull_request' run: | RESPONSE=$(curl -s -L \ -H "Accept: application/vnd.github+json" \ From af4cb32344db3b3e659c1f2fe259e4f10b960054 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 03:13:33 +0000 Subject: [PATCH 05/21] Fix path to sage_docbuild --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 37c48ea8a95..50df57e1824 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -113,7 +113,7 @@ jobs: # mathjax path in old doc (regex) mathjax_path_from="[-./A-Za-z_]*/tex-chtml[.]js?v=[0-9a-f]*" # mathjax path in new doc - mathjax_path_to=$(SAGE_USE_CDNS=yes python -c "from sage_docbuild.conf import mathjax_path; print(mathjax_path)") + mathjax_path_to=$(SAGE_USE_CDNS=yes python -c "from src.sage_docbuild.conf import mathjax_path; print(mathjax_path)") new_version=$(cat src/VERSION.txt) # Wipe out chronic diffs between old doc and new doc (cd doc && \ From 0470c2f2f9d97346ea5854ffae7fd78d898a8ef8 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 03:43:15 +0000 Subject: [PATCH 06/21] Add shell specification for storing old documentation --- .github/workflows/doc-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 50df57e1824..d83403930f9 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -98,6 +98,7 @@ jobs: - name: Store old doc id: worktree if: steps.download-doc.outcome == 'success' + shell: bash -l {0} run: | git config --global --add safe.directory $(pwd) git config --global user.email "ci-sage@example.com" From 199be4ebe2afc95563c6969ea887752f45311592 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 06:11:51 +0000 Subject: [PATCH 07/21] Try with editable install --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index d83403930f9..ed298afce7c 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -68,7 +68,7 @@ jobs: run: | export LIB="$LIB;$CONDA_PREFIX\\Library\\lib" export INCLUDE="$INCLUDE;$CONDA_PREFIX\\Library\\include" - pip install --no-build-isolation --config-settings=builddir=builddir . -v + pip install --no-build-isolation --config-settings=builddir=builddir --editable . -v # # For pull requests From dd44ea75691c26fc6cc8d53326f1b27b3c922c1e Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 06:12:41 +0000 Subject: [PATCH 08/21] Fix directory creation --- src/sage_docbuild/builders.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index 99a81e7b851..19bd238b2bc 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -935,16 +935,15 @@ def write_auto_rest_file(self, module_name: str): """ if not module_name.startswith('sage'): return - filename = self.auto_rest_filename(module_name) - os.makedirs(os.path.dirname(filename), exist_ok=True) title = self.get_module_docstring_title(module_name) - if title == '': logger.error("Warning: Missing title for %s", module_name) title = "MISSING TITLE" - with open(filename, 'w') as outfile: + rst_file = self.auto_rest_filename(module_name) + rst_file.parent.mkdir(parents=True, exist_ok=True) + with rst_file.open('w') as outfile: # Don't doctest the autogenerated file. outfile.write(".. nodoctest\n\n") # Now write the actual content. From 5ee3c51eb26dda1f952e9795b15789b65524724a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 07:54:54 +0000 Subject: [PATCH 09/21] add copybutton conda pkg --- environment-3.11-linux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment-3.11-linux.yml b/environment-3.11-linux.yml index 65175bd603b..92f8043b3d7 100644 --- a/environment-3.11-linux.yml +++ b/environment-3.11-linux.yml @@ -329,6 +329,7 @@ dependencies: - soupsieve=2.5=pyhd8ed1ab_1 - sphinx=8.2.3=pyhd8ed1ab_0 - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_3 + - sphinx-copybutton=0.5.2=pyhd8ed1ab_1 - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_1 - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 From 7550538ef0e87ba5df780efe3fefe3dd96f7e653 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 08:05:47 +0000 Subject: [PATCH 10/21] Work with absolute paths everywhere --- src/sage_docbuild/__main__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage_docbuild/__main__.py b/src/sage_docbuild/__main__.py index 3b7d74548f6..bb67ac907d0 100644 --- a/src/sage_docbuild/__main__.py +++ b/src/sage_docbuild/__main__.py @@ -456,6 +456,7 @@ def main(): # Check that the docs source directory exists if args.source_dir is None: args.source_dir = Path(os.environ.get('SAGE_DOC_SRC', 'src/doc')) + args.source_dir = args.source_dir.absolute() if not args.source_dir.is_dir(): parser.error(f"Source directory {args.source_dir} does not exist.") @@ -472,7 +473,8 @@ def main(): # Check that the docs output directory exists if args.output_dir is None: - args.output_dir = Path(os.environ.get('SAGE_DOC', 'src/doc')) + args.output_dir = Path(os.environ.get('SAGE_DOC', 'src/doc')) + args.output_dir = args.output_dir.absolute() if not args.output_dir.exists(): try: args.output_dir.mkdir(parents=True) @@ -519,8 +521,8 @@ def excepthook(*exc_info): os.environ['SAGE_SKIP_TESTS_BLOCKS'] = 'True' if args.use_cdns: os.environ['SAGE_USE_CDNS'] = 'yes' - os.environ['SAGE_DOC_SRC'] = str(args.source_dir.absolute()) - os.environ['SAGE_DOC'] = str(args.output_dir.absolute()) + os.environ['SAGE_DOC_SRC'] = str(args.source_dir) + os.environ['SAGE_DOC'] = str(args.output_dir) build_options.ABORT_ON_ERROR = not args.keep_going From 230fd8fad39d047684f5713cfceaa3686e0a1bb5 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 11:09:10 +0000 Subject: [PATCH 11/21] Add dependency for 'reference_top' on other reference docs --- src/doc/meson.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/meson.build b/src/doc/meson.build index 3a8922456f8..3f1da8619c2 100644 --- a/src/doc/meson.build +++ b/src/doc/meson.build @@ -38,6 +38,9 @@ foreach type : ['inventory', 'html', 'pdf'] if short_ref != 'references' deps += bibliography endif + if short_ref == 'reference_top' + deps += reference_inventory + endif target = custom_target( 'doc-' + type + '-reference-' + short_ref, output: [type + short_ref], From ee77f038ba6b2dccb0a76a1b236b56e1f47453dd Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 21 Apr 2025 11:16:56 +0000 Subject: [PATCH 12/21] Exclude 'reference_top' from the list of other documents in doc-inventory-reference --- src/doc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/Makefile b/src/doc/Makefile index 395a70de68b..47a843cb591 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -40,7 +40,7 @@ doc-inventory-reference: doc-src $(eval DOCS = $(shell sage --docbuild --all-documents reference)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi $(eval BIBLIO = $(firstword $(DOCS))) - $(eval OTHER_DOCS = $(wordlist 2, 100, $(DOCS))) + $(eval OTHER_DOCS = $(filter-out reference_top, $(wordlist 2, 100, $(DOCS)))) $(MAKE) doc-inventory--$(subst /,-,$(BIBLIO)) $(MAKE) $(foreach doc, $(OTHER_DOCS), doc-inventory--$(subst /,-,$(doc))) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-inventory--reference_top From f71e2825c0abc9b0cbac15f010c0c94ab9ddafe1 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 17 May 2025 02:11:03 +0000 Subject: [PATCH 13/21] Improve dependency handling --- src/doc/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/meson.build b/src/doc/meson.build index 3f1da8619c2..e23c2bd6962 100644 --- a/src/doc/meson.build +++ b/src/doc/meson.build @@ -31,7 +31,8 @@ foreach type : ['inventory', 'html', 'pdf'] else short_ref = ref endif - deps = [doc_src] + deps = [] + deps += doc_src if type == 'html' or type == 'pdf' deps += reference_inventory endif From 327a7bb4a761cfefd370bc59f352461eef05dc8b Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 17 May 2025 02:28:44 +0000 Subject: [PATCH 14/21] Add dependency of 'top' docs on all other references --- src/doc/meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/doc/meson.build b/src/doc/meson.build index e23c2bd6962..dedbe0b60c0 100644 --- a/src/doc/meson.build +++ b/src/doc/meson.build @@ -41,6 +41,11 @@ foreach type : ['inventory', 'html', 'pdf'] endif if short_ref == 'reference_top' deps += reference_inventory + if type == 'html' + deps += reference_html + elif type == 'pdf' + deps += reference_pdf + endif endif target = custom_target( 'doc-' + type + '-reference-' + short_ref, From f6d186b137f394b691c776f9545d90ddc0ca6d34 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 17 May 2025 02:39:05 +0000 Subject: [PATCH 15/21] Use ccache to build sage --- .github/workflows/doc-build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index ed298afce7c..bb3b2966c4d 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -66,10 +66,11 @@ jobs: - name: Build Sage shell: bash -l {0} run: | - export LIB="$LIB;$CONDA_PREFIX\\Library\\lib" - export INCLUDE="$INCLUDE;$CONDA_PREFIX\\Library\\include" + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + export CC="ccache $CC" + export CXX="ccache $CXX" pip install --no-build-isolation --config-settings=builddir=builddir --editable . -v - + # # For pull requests # From 5a3c014c78bb007a86d76d4dc0b900b8f1584220 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 17 May 2025 04:12:06 +0000 Subject: [PATCH 16/21] Don't create neasted doc directories --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index bb3b2966c4d..135ea51dc54 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -155,7 +155,7 @@ jobs: if [ -d "doc/html" ]; then rm -rf doc/html fi - cp -r builddir/src/doc doc/ + cp -r builddir/src/doc/* doc/ # Check if we are on pull request event PR_NUMBER="" if [[ -n "$GITHUB_REF" ]]; then From 1ef0ae74c6ab98cba310a3c467bbe5897143beef Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 7 Jun 2025 17:10:13 +0800 Subject: [PATCH 17/21] Fix tests --- src/sage_docbuild/__main__.py | 2 +- src/sage_docbuild/builders.py | 89 +++++++++++++++-------------------- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/src/sage_docbuild/__main__.py b/src/sage_docbuild/__main__.py index bb67ac907d0..6459596a28b 100644 --- a/src/sage_docbuild/__main__.py +++ b/src/sage_docbuild/__main__.py @@ -180,7 +180,7 @@ def get_formats(): Return a list of output formats the Sage documentation builder will accept on the command-line. """ - tut_b = DocBuilder('en/tutorial') + tut_b = DocBuilder('en/tutorial', BuildOptions()) formats = tut_b._output_formats() formats.remove('html') return ['html', 'pdf'] + formats diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index 6dba55d0901..353e170b243 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -104,31 +104,6 @@ def builder_helper(type): """ Return a function which builds the documentation for output type ``type``. - - TESTS: - - Check that :issue:`25161` has been resolved:: - - sage: from sage_docbuild.builders import DocBuilder - sage: from sage_docbuild.__main__ import setup_parser - sage: DocBuilder._options = setup_parser().parse_args([]) # builder_helper needs _options to be set - - sage: import sage_docbuild.sphinxbuild - sage: def raiseBaseException(): - ....: raise BaseException("abort pool operation") - sage: original_runsphinx, sage_docbuild.sphinxbuild.runsphinx = sage_docbuild.sphinxbuild.runsphinx, raiseBaseException - - sage: from sage.misc.temporary_file import tmp_dir - sage: os.environ['SAGE_DOC'] = tmp_dir() - sage: sage.env.var('SAGE_DOC') # random - sage: from sage_docbuild.builders import builder_helper, build_ref_doc - sage: from sage_docbuild.builders import _build_many as build_many - sage: helper = builder_helper("html") - sage: try: # optional - sagemath_doc_html - ....: build_many(build_ref_doc, [("docname", "en", "html", {})]) - ....: except Exception as E: - ....: "Non-exception during docbuild: abort pool operation" in str(E) - True """ def f(self, *args, **kwds): output_dir = self._output_dir(type) @@ -200,9 +175,13 @@ def _output_dir(self, type): EXAMPLES:: sage: from sage_docbuild.builders import DocBuilder - sage: b = DocBuilder('en/tutorial') - sage: b._output_dir('html') # optional - sagemath_doc_html - '.../html/en/tutorial' + sage: from sage_docbuild.build_options import BuildOptions + sage: import tempfile + sage: with tempfile.TemporaryDirectory() as directory: + ....: options = BuildOptions(output_dir=Path(directory), source_dir=Path('src/doc')) + ....: builder = DocBuilder('en/tutorial', options) + ....: builder._output_dir('html') + ...Path('.../html/en/tutorial') """ dir = self._options.output_dir / type / self.name dir.mkdir(parents=True, exist_ok=True) @@ -218,9 +197,13 @@ def _doctrees_dir(self) -> Path: EXAMPLES:: sage: from sage_docbuild.builders import DocBuilder - sage: b = DocBuilder('tutorial') - sage: b._doctrees_dir() # optional - sagemath_doc_html - '.../doctrees/en/tutorial' + sage: from sage_docbuild.build_options import BuildOptions + sage: import tempfile + sage: with tempfile.TemporaryDirectory() as directory: + ....: options = BuildOptions(output_dir=Path(directory), source_dir=Path('src/doc')) + ....: builder = DocBuilder('en/tutorial', options) + ....: builder._doctrees_dir() + ...Path('.../doctrees/en/tutorial') """ dir = self._options.output_dir / 'doctrees' / self.name dir.mkdir(parents=True, exist_ok=True) @@ -233,8 +216,10 @@ def _output_formats(self): EXAMPLES:: sage: from sage_docbuild.builders import DocBuilder - sage: b = DocBuilder('tutorial') - sage: b._output_formats() + sage: from sage_docbuild.build_options import BuildOptions + sage: options = BuildOptions(source_dir=Path('src/doc')) + sage: builder = DocBuilder('tutorial', options) + sage: builder._output_formats() ['changes', 'html', 'htmlhelp', 'inventory', 'json', 'latex', 'linkcheck', 'pickle', 'web'] """ # Go through all the attributes of self and check to @@ -257,8 +242,10 @@ def pdf(self): EXAMPLES:: sage: from sage_docbuild.builders import DocBuilder - sage: b = DocBuilder('tutorial') - sage: b.pdf() #not tested + sage: from sage_docbuild.build_options import BuildOptions + sage: options = BuildOptions(source_dir = Path('src/doc')) + sage: builder = DocBuilder('tutorial', options) + sage: builder.pdf() #not tested """ self.latex() tex_dir = self._output_dir('latex') @@ -421,12 +408,15 @@ def _output_dir(self, type: Literal['html', 'latex', 'pdf']) -> Path: EXAMPLES:: sage: from sage_docbuild.builders import ReferenceBuilder - sage: b = ReferenceBuilder('reference') - sage: b._output_dir('html') # optional - sagemath_doc_html - '.../html/en/reference' + sage: import tempfile + sage: with tempfile.TemporaryDirectory() as directory: + ....: options = BuildOptions(output_dir = Path(directory)) + ....: builder = ReferenceBuilder('reference', options) + ....: builder._output_dir('html') + ...Path('.../html/reference') """ dir = self.options.output_dir / type / self.name - dir.mkdir(exist_ok=True) + dir.mkdir(parents=True, exist_ok=True) return dir def _source_dir(self) -> Path: @@ -904,8 +894,10 @@ def auto_rest_filename(self, module_name: str) -> Path: EXAMPLES:: sage: from sage_docbuild.builders import ReferenceSubBuilder - sage: ReferenceSubBuilder("reference").auto_rest_filename("sage.combinat.partition") - '.../en/reference/sage/combinat/partition.rst' + sage: from sage_docbuild.build_options import BuildOptions + sage: options = BuildOptions(source_dir = Path('src/doc')) + sage: ReferenceSubBuilder("reference", options).auto_rest_filename("sage.combinat.partition") + ...Path('src/doc/en/reference/sage/combinat/partition.rst') """ return self.dir / (module_name.replace('.', os.path.sep) + '.rst') @@ -1163,10 +1155,8 @@ def get_all_documents(source: Path) -> list[Path]: EXAMPLES:: sage: from sage_docbuild.builders import get_all_documents - sage: documents = get_all_documents() - sage: 'en/tutorial' in documents # optional - sage_spkg - True - sage: documents[0] == 'en/reference' + sage: documents = get_all_documents(Path('src/doc')) + sage: Path('en/tutorial') in documents True """ documents = [] @@ -1197,12 +1187,9 @@ def get_all_reference_documents(source: Path) -> list[Path]: EXAMPLES:: - sage: refdir = Path(os.environ['SAGE_DOC_SRC']) / 'en' # optional - sage_spkg - sage: sorted(get_all_reference_documents(refdir)) # optional - sage_spkg - ['reference/algebras', - 'reference/arithgroup', - ..., - 'reference/valuations'] + sage: documents = get_all_reference_documents(Path('src/doc/en')) + sage: Path('reference/algebras') in documents + True """ documents: list[tuple[int, Path]] = [] From 6ef056e0f67577c1c2bca14184a963b936378ac8 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 9 Jun 2025 08:10:18 +0200 Subject: [PATCH 18/21] Make `Path` available to all doctests --- src/sage/repl/ipython_kernel/all_jupyter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/repl/ipython_kernel/all_jupyter.py b/src/sage/repl/ipython_kernel/all_jupyter.py index 2d2677da27d..03c7af72c96 100644 --- a/src/sage/repl/ipython_kernel/all_jupyter.py +++ b/src/sage/repl/ipython_kernel/all_jupyter.py @@ -8,3 +8,5 @@ from sage.repl.ipython_kernel.widgets_sagenb import (input_box, text_control, slider, range_slider, checkbox, selector, input_grid, color_selector) from sage.repl.ipython_kernel.interact import interact + +from pathlib import Path \ No newline at end of file From a5d76628504cef87ed1f331b01d924eb15c59dde Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 9 Jun 2025 08:41:40 +0200 Subject: [PATCH 19/21] More doctest fixes --- src/sage_docbuild/builders.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index 353e170b243..91035a01f1c 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -408,6 +408,7 @@ def _output_dir(self, type: Literal['html', 'latex', 'pdf']) -> Path: EXAMPLES:: sage: from sage_docbuild.builders import ReferenceBuilder + sage: from sage_docbuild.build_options import BuildOptions sage: import tempfile sage: with tempfile.TemporaryDirectory() as directory: ....: options = BuildOptions(output_dir = Path(directory)) @@ -1187,6 +1188,7 @@ def get_all_reference_documents(source: Path) -> list[Path]: EXAMPLES:: + sage: from sage_docbuild.builders import get_all_reference_documents sage: documents = get_all_reference_documents(Path('src/doc/en')) sage: Path('reference/algebras') in documents True From efc1dd9c9216ecdc2b28d257ea56ccd90ad971bd Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 23 Jun 2025 13:48:31 +0200 Subject: [PATCH 20/21] Update primecountpy in uv --- pyproject.toml | 1 + uv.lock | 239 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 227 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0f35be4a636..7d626b54be7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -202,6 +202,7 @@ dev = [ "conda-lock", "grayskull", "toml", + "uv", ] [tool.ruff] diff --git a/uv.lock b/uv.lock index fc28bc156a7..606a880b80c 100644 --- a/uv.lock +++ b/uv.lock @@ -440,6 +440,7 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/cd/25/4ce80c78963834b8a9fd1cc1266be5ed8d1840785c0f2e1b73b8d128d505/cryptography-44.0.2.tar.gz", hash = "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0", size = 710807, upload-time = "2025-03-02T00:01:37.692Z" } wheels = [ + { url = "https://files.pythonhosted.org/packages/92/ef/83e632cfa801b221570c5f58c0369db6fa6cef7d9ff859feab1aae1a8a0f/cryptography-44.0.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7", size = 6676361, upload-time = "2025-03-02T00:00:06.528Z" }, { url = "https://files.pythonhosted.org/packages/30/ec/7ea7c1e4c8fc8329506b46c6c4a52e2f20318425d48e0fe597977c71dbce/cryptography-44.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1", size = 3952350, upload-time = "2025-03-02T00:00:09.537Z" }, { url = "https://files.pythonhosted.org/packages/27/61/72e3afdb3c5ac510330feba4fc1faa0fe62e070592d6ad00c40bb69165e5/cryptography-44.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb", size = 4166572, upload-time = "2025-03-02T00:00:12.03Z" }, { url = "https://files.pythonhosted.org/packages/26/e4/ba680f0b35ed4a07d87f9e98f3ebccb05091f3bf6b5a478b943253b3bbd5/cryptography-44.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843", size = 3958124, upload-time = "2025-03-02T00:00:14.518Z" }, @@ -449,6 +450,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bb/6d/858e356a49a4f0b591bd6789d821427de18432212e137290b6d8a817e9bf/cryptography-44.0.2-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308", size = 4191753, upload-time = "2025-03-02T00:00:25.038Z" }, { url = "https://files.pythonhosted.org/packages/b2/80/62df41ba4916067fa6b125aa8c14d7e9181773f0d5d0bd4dcef580d8b7c6/cryptography-44.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688", size = 4079550, upload-time = "2025-03-02T00:00:26.929Z" }, { url = "https://files.pythonhosted.org/packages/f3/cd/2558cc08f7b1bb40683f99ff4327f8dcfc7de3affc669e9065e14824511b/cryptography-44.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7", size = 4298367, upload-time = "2025-03-02T00:00:28.735Z" }, + { url = "https://files.pythonhosted.org/packages/71/59/94ccc74788945bc3bd4cf355d19867e8057ff5fdbcac781b1ff95b700fb1/cryptography-44.0.2-cp37-abi3-win32.whl", hash = "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79", size = 2772843, upload-time = "2025-03-02T00:00:30.592Z" }, + { url = "https://files.pythonhosted.org/packages/ca/2c/0d0bbaf61ba05acb32f0841853cfa33ebb7a9ab3d9ed8bb004bd39f2da6a/cryptography-44.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa", size = 3209057, upload-time = "2025-03-02T00:00:33.393Z" }, + { url = "https://files.pythonhosted.org/packages/9e/be/7a26142e6d0f7683d8a382dd963745e65db895a79a280a30525ec92be890/cryptography-44.0.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3", size = 6677789, upload-time = "2025-03-02T00:00:36.009Z" }, { url = "https://files.pythonhosted.org/packages/06/88/638865be7198a84a7713950b1db7343391c6066a20e614f8fa286eb178ed/cryptography-44.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639", size = 3951919, upload-time = "2025-03-02T00:00:38.581Z" }, { url = "https://files.pythonhosted.org/packages/d7/fc/99fe639bcdf58561dfad1faa8a7369d1dc13f20acd78371bb97a01613585/cryptography-44.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd", size = 4167812, upload-time = "2025-03-02T00:00:42.934Z" }, { url = "https://files.pythonhosted.org/packages/53/7b/aafe60210ec93d5d7f552592a28192e51d3c6b6be449e7fd0a91399b5d07/cryptography-44.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181", size = 3958571, upload-time = "2025-03-02T00:00:46.026Z" }, @@ -458,6 +462,8 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/89/33/c1cf182c152e1d262cac56850939530c05ca6c8d149aa0dcee490b417e99/cryptography-44.0.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23", size = 4193906, upload-time = "2025-03-02T00:00:56.49Z" }, { url = "https://files.pythonhosted.org/packages/e1/99/87cf26d4f125380dc674233971069bc28d19b07f7755b29861570e513650/cryptography-44.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922", size = 4081572, upload-time = "2025-03-02T00:00:59.995Z" }, { url = "https://files.pythonhosted.org/packages/b3/9f/6a3e0391957cc0c5f84aef9fbdd763035f2b52e998a53f99345e3ac69312/cryptography-44.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4", size = 4298631, upload-time = "2025-03-02T00:01:01.623Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a5/5bc097adb4b6d22a24dea53c51f37e480aaec3465285c253098642696423/cryptography-44.0.2-cp39-abi3-win32.whl", hash = "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5", size = 2773792, upload-time = "2025-03-02T00:01:04.133Z" }, + { url = "https://files.pythonhosted.org/packages/33/cf/1f7649b8b9a3543e042d3f348e398a061923ac05b507f3f4d95f11938aa9/cryptography-44.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6", size = 3210957, upload-time = "2025-03-02T00:01:06.987Z" }, { url = "https://files.pythonhosted.org/packages/d6/d7/f30e75a6aa7d0f65031886fa4a1485c2fbfe25a1896953920f6a9cfe2d3b/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d", size = 3887513, upload-time = "2025-03-02T00:01:22.911Z" }, { url = "https://files.pythonhosted.org/packages/9c/b4/7a494ce1032323ca9db9a3661894c66e0d7142ad2079a4249303402d8c71/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471", size = 4107432, upload-time = "2025-03-02T00:01:24.701Z" }, { url = "https://files.pythonhosted.org/packages/45/f8/6b3ec0bc56123b344a8d2b3264a325646d2dcdbdd9848b5e6f3d37db90b3/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615", size = 3891421, upload-time = "2025-03-02T00:01:26.335Z" }, @@ -565,6 +571,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] +[[package]] +name = "deprecated" +version = "1.2.18" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, +] + [[package]] name = "distlib" version = "0.3.9" @@ -1286,6 +1304,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/61/1c/f35be80754e2da778c384e046b867e0b39393bd58e43f803aff461504002/memory_allocator-0.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:72fb526f5e60e75a9c3878dccb705233cddc94f33cac6e83d33af4b8f5e24b11", size = 543957, upload-time = "2024-03-24T18:43:16.189Z" }, ] +[[package]] +name = "meson" +version = "1.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/58/fedcfbc958585381281f72b4866288f04c3f109a6a8757e0a529af8aaa79/meson-1.8.2.tar.gz", hash = "sha256:c105816d8158c76b72adcb9ff60297719096da7d07f6b1f000fd8c013cd387af", size = 2335538, upload-time = "2025-06-09T20:43:25.172Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/6e/b9dfeac98dd508f88bcaff134ee0bf5e602caf3ccb5a12b5dd9466206df1/meson-1.8.2-py3-none-any.whl", hash = "sha256:274b49dbe26e00c9a591442dd30f4ae9da8ce11ce53d0f4682cd10a45d50f6fd", size = 1013517, upload-time = "2025-06-09T20:43:21.987Z" }, +] + [[package]] name = "more-itertools" version = "10.6.0" @@ -1566,13 +1593,32 @@ wheels = [ [[package]] name = "primecountpy" -version = "0.1.0" +version = "0.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cysignals" }, - { name = "cython" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/94/d5d3440bb212c05ebb7aa68337a28a3a101b7c0c3458e1f6ca6ee7d62589/primecountpy-0.1.0.tar.gz", hash = "sha256:78fe7cc32115f0669a45d7c90faaf39f7ce3939e39e2e7e5f14c17fe4bff0676", size = 16070, upload-time = "2021-12-01T11:31:39.823Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/99/a705fe480cfdccd697682d126972f401ec43922da0ee7a06aafd29a12d98/primecountpy-0.1.1.tar.gz", hash = "sha256:c8561817c0be86eeffc41b97b6ef617d795f72cf3de59d9234d1c83d7e424030", size = 117697, upload-time = "2025-05-21T01:37:21.26Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/28/15712dd9757a761a5b500f8d4dad963b3a90019d24732a0bf1ecd0465e2f/primecountpy-0.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:873256caaba77467aecacfd9e41e3f68b44bf6dfb9e2a5c633a61d99507fdb8f", size = 253237, upload-time = "2025-05-20T21:20:59.28Z" }, + { url = "https://files.pythonhosted.org/packages/00/cf/eb1210283bc81cfc6664eaca36280ff0dbc8e8322d33345c34990a4a4fad/primecountpy-0.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:38f89d08ac298eb67ce089f3fca4bb24bb11e13b39b5b8edfa7256f9fb12db1e", size = 207669, upload-time = "2025-05-20T21:21:00.964Z" }, + { url = "https://files.pythonhosted.org/packages/45/2e/738e5b4fc2130794c9f6a9a5d5c8af3d6925dbe749490c1ed449ca2bac0b/primecountpy-0.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31d0516f3ae24cba0e21c5c496c54111849e912f88b7df694b67dd5d5c3a48a4", size = 509839, upload-time = "2025-05-20T21:21:02.746Z" }, + { url = "https://files.pythonhosted.org/packages/25/49/f0c28d1cd48c502ac64d92d5c2f913382c57c330f55b639a3f62abe65a52/primecountpy-0.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b62a008d75ac37ba34fcbefeb90757321f20b92f50eda37798aa2f047a31625", size = 498406, upload-time = "2025-05-20T21:21:04.376Z" }, + { url = "https://files.pythonhosted.org/packages/d3/4c/ac8a5cf4703cace93b6adc72d54e1389e0ccd84ade99ab83836b52f54577/primecountpy-0.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5bbb6aa1c7b933e787e7febb4865846623d985c452c157a881b5eff76cf07d63", size = 1639827, upload-time = "2025-05-20T21:21:06.136Z" }, + { url = "https://files.pythonhosted.org/packages/84/d4/0c921167799ff70e7afa43e1ce8a2f1f20e33d8dd2df68013b65e82b57a9/primecountpy-0.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8ed16ed1be6dfc7a401aa9717dadd21cffbba447935e6ef90a6ad6d7ca6ca7ce", size = 1511549, upload-time = "2025-05-20T21:21:07.569Z" }, + { url = "https://files.pythonhosted.org/packages/93/da/4ebab502b31bfc4274581f26b9008bd37d81df90437f0d33665ee249fe04/primecountpy-0.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a52e266019ae1505789256ecef6cf0e470f42594291ad627dfa86e7e05b772e9", size = 314061, upload-time = "2025-05-20T21:21:09.152Z" }, + { url = "https://files.pythonhosted.org/packages/80/37/16a2b10fcada8a5bcaa903717a15a01488f5f2a8f4c35ed09f1b02ce27f1/primecountpy-0.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:210bac4fa0c9fee5ab521527c50d8fe2f3a2feb2009b14f49a47a415130ebb07", size = 268350, upload-time = "2025-05-20T21:21:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/69/10/d9b5743b4979f271a51f1f4d85988bbfcb2902fe92c988ceb7a96b448e50/primecountpy-0.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b709cee8f5416c72e15653593e182a032fa3d56927c10eacb4660c9d18e34e21", size = 575324, upload-time = "2025-05-20T21:21:12.24Z" }, + { url = "https://files.pythonhosted.org/packages/17/26/8eb1620ec8d51ee4e5a5e6d3953091a6b1dcfbcf0a29bafa5915262b1b4b/primecountpy-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f4692d97f2d3d5fa29939b701ebb49e6c9443e3a6838f480450b53fec5a71d1", size = 564766, upload-time = "2025-05-20T21:21:13.911Z" }, + { url = "https://files.pythonhosted.org/packages/36/33/db12d95d8585608078c5910ac2ddbecbfffe114ab74a038f04b712278e02/primecountpy-0.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:06bac97a76989ff16f6ff36a753c60257c151d8fc7e11a481c2400f7c9a224ff", size = 1704010, upload-time = "2025-05-20T21:21:15.919Z" }, + { url = "https://files.pythonhosted.org/packages/d1/03/e0e5ea483e0bca96a09aa88f2f20cd683aa39f4293f43a2dd81c7831e5e4/primecountpy-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:986142d5521fa2bc30287380d9cbbf97298780a81dca61d9f710ca0bb1676e64", size = 1577735, upload-time = "2025-05-20T21:21:18.563Z" }, + { url = "https://files.pythonhosted.org/packages/05/d7/18a688573c8b4413e27a0ed01d537bf245f7b5a4bc1fbe94b3f5214ebc44/primecountpy-0.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8eb12b93834683369ab7e6ce37a0960042c6c1a1190860a77dd63194f3e4aae4", size = 313579, upload-time = "2025-05-22T03:01:08.732Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d8/3e6d46e33c053919810f7ad8c532660a287e196a42e099ecd8638c9a2c19/primecountpy-0.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d260e96cddf02e0c226da50d9cd9271442c9a4a2942325b93227a0017b1c3df9", size = 267885, upload-time = "2025-05-22T03:01:09.913Z" }, + { url = "https://files.pythonhosted.org/packages/88/c1/4f808e4df2ad3542116638eedbae459ed1cd1f618582d6fd4aa1172b851d/primecountpy-0.1.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9965714dae6273dd0fd0b4fe74b7223ef25bf299337d0d0abd3e8d6cbf39993", size = 570494, upload-time = "2025-05-22T03:01:11.902Z" }, + { url = "https://files.pythonhosted.org/packages/3b/7c/dbcc48d23a39daa6877fe07bd6e547f4135de5a38446f349cdbf3f094560/primecountpy-0.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c50297b20943d7cbce610746b2588e99bd88f1f30a79f314c3537301ccc27a", size = 564334, upload-time = "2025-05-22T03:01:13.328Z" }, + { url = "https://files.pythonhosted.org/packages/a2/22/8df2e868c4f5ebce834f44574da01415187b27587ff616473ba8ee6f8b72/primecountpy-0.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:eb7ccbd254cc9de54957e9c6866ab8a4983f59c61a41c9cc26ba7e1b422038ba", size = 1698746, upload-time = "2025-05-22T03:01:15.128Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7e/2b671e557f6c7c21bfdea07dd2a3f6cfa85a09f89bd4cdc3171ccc5e5184/primecountpy-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75a791d7337d8b104edaab1d772debcdcc04e541da4245a9480116ef5bff6ef0", size = 1573515, upload-time = "2025-05-22T03:01:16.959Z" }, +] [[package]] name = "progressbar2" @@ -1725,6 +1771,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725, upload-time = "2024-01-05T00:28:45.903Z" }, ] +[[package]] +name = "pygithub" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecated" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "pynacl" }, + { name = "requests" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/88/e08ab18dc74b2916f48703ed1a797d57cb64eca0e23b0a9254e13cfe3911/pygithub-2.6.1.tar.gz", hash = "sha256:b5c035392991cca63959e9453286b41b54d83bf2de2daa7d7ff7e4312cebf3bf", size = 3659473, upload-time = "2025-02-21T13:45:58.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/fc/a444cd19ccc8c4946a512f3827ed0b3565c88488719d800d54a75d541c0b/PyGithub-2.6.1-py3-none-any.whl", hash = "sha256:6f2fa6d076ccae475f9fc392cc6cdbd54db985d4f69b8833a28397de75ed6ca3", size = 410451, upload-time = "2025-02-21T13:45:55.519Z" }, +] + [[package]] name = "pygments" version = "2.19.1" @@ -1734,6 +1797,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, ] +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + [[package]] name = "pylev" version = "1.4.0" @@ -1743,6 +1820,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/78/95cfe72991d22994f0ec5a3b742b31c95a28344d33e06b69406b68398a29/pylev-1.4.0-py2.py3-none-any.whl", hash = "sha256:7b2e2aa7b00e05bb3f7650eb506fc89f474f70493271a35c242d9a92188ad3dd", size = 6080, upload-time = "2021-05-30T20:07:58.473Z" }, ] +[[package]] +name = "pynacl" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/22/27582568be639dfe22ddb3902225f91f2f17ceff88ce80e4db396c8986da/PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba", size = 3392854, upload-time = "2022-01-07T22:05:41.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/75/0b8ede18506041c0bf23ac4d8e2971b4161cd6ce630b177d0a08eb0d8857/PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1", size = 349920, upload-time = "2022-01-07T22:05:49.156Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/fddf10acd09637327a97ef89d2a9d621328850a72f1fdc8c08bdf72e385f/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92", size = 601722, upload-time = "2022-01-07T22:05:50.989Z" }, + { url = "https://files.pythonhosted.org/packages/5d/70/87a065c37cca41a75f2ce113a5a2c2aa7533be648b184ade58971b5f7ccc/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394", size = 680087, upload-time = "2022-01-07T22:05:52.539Z" }, + { url = "https://files.pythonhosted.org/packages/ee/87/f1bb6a595f14a327e8285b9eb54d41fef76c585a0edef0a45f6fc95de125/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d", size = 856678, upload-time = "2022-01-07T22:05:54.251Z" }, + { url = "https://files.pythonhosted.org/packages/66/28/ca86676b69bf9f90e710571b67450508484388bfce09acf8a46f0b8c785f/PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858", size = 1133660, upload-time = "2022-01-07T22:05:56.056Z" }, + { url = "https://files.pythonhosted.org/packages/3d/85/c262db650e86812585e2bc59e497a8f59948a005325a11bbbc9ecd3fe26b/PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b", size = 663824, upload-time = "2022-01-07T22:05:57.434Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1a/cc308a884bd299b651f1633acb978e8596c71c33ca85e9dc9fa33a5399b9/PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff", size = 1117912, upload-time = "2022-01-07T22:05:58.665Z" }, + { url = "https://files.pythonhosted.org/packages/25/2d/b7df6ddb0c2a33afdb358f8af6ea3b8c4d1196ca45497dd37a56f0c122be/PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543", size = 204624, upload-time = "2022-01-07T22:06:00.085Z" }, + { url = "https://files.pythonhosted.org/packages/5e/22/d3db169895faaf3e2eda892f005f433a62db2decbcfbc2f61e6517adfa87/PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", size = 212141, upload-time = "2022-01-07T22:06:01.861Z" }, +] + [[package]] name = "pyparsing" version = "3.2.1" @@ -2140,16 +2237,16 @@ name = "sagemath" source = { editable = "." } dependencies = [ { name = "conway-polynomials" }, - { name = "cypari2" }, + { name = "cypari2", marker = "sys_platform != 'win32'" }, { name = "cysignals" }, { name = "cython" }, - { name = "fpylll" }, + { name = "fpylll", marker = "sys_platform != 'win32'" }, { name = "gmpy2" }, { name = "ipykernel" }, { name = "ipython" }, { name = "ipywidgets" }, { name = "jupyter-client" }, - { name = "lrcalc" }, + { name = "lrcalc", marker = "sys_platform != 'win32'" }, { name = "matplotlib" }, { name = "memory-allocator" }, { name = "mpmath" }, @@ -2158,8 +2255,9 @@ dependencies = [ { name = "pexpect" }, { name = "pillow" }, { name = "pkgconfig" }, - { name = "pplpy" }, - { name = "primecountpy" }, + { name = "platformdirs" }, + { name = "pplpy", marker = "sys_platform != 'win32'" }, + { name = "primecountpy", marker = "sys_platform != 'win32'" }, { name = "ptyprocess" }, { name = "requests" }, { name = "scipy" }, @@ -2178,11 +2276,17 @@ r = [ dev = [ { name = "conda-lock" }, { name = "grayskull" }, + { name = "meson" }, + { name = "pygithub" }, { name = "toml" }, + { name = "tqdm" }, + { name = "uv" }, ] docs = [ { name = "furo" }, + { name = "python-dateutil" }, { name = "sphinx" }, + { name = "sphinx-copybutton" }, { name = "sphinx-inline-tabs" }, ] lint = [ @@ -2200,16 +2304,16 @@ test = [ [package.metadata] requires-dist = [ { name = "conway-polynomials", specifier = ">=0.8" }, - { name = "cypari2", specifier = ">=2.2.1" }, + { name = "cypari2", marker = "sys_platform != 'win32'", specifier = ">=2.2.1" }, { name = "cysignals", specifier = ">=1.11.2,!=1.12.0" }, { name = "cython", specifier = ">=3.0,!=3.0.3" }, - { name = "fpylll", specifier = ">=0.5.9" }, + { name = "fpylll", marker = "sys_platform != 'win32'", specifier = ">=0.5.9" }, { name = "gmpy2", specifier = "~=2.1b999" }, { name = "ipykernel", specifier = ">=5.2.1" }, { name = "ipython", specifier = ">=8.9.0" }, { name = "ipywidgets", specifier = ">=7.5.1" }, { name = "jupyter-client" }, - { name = "lrcalc", specifier = "~=2.1" }, + { name = "lrcalc", marker = "sys_platform != 'win32'", specifier = "~=2.1" }, { name = "matplotlib", specifier = ">=3.7.0" }, { name = "memory-allocator" }, { name = "mpmath", specifier = ">=1.1.0" }, @@ -2218,8 +2322,9 @@ requires-dist = [ { name = "pexpect", specifier = ">=4.8.0" }, { name = "pillow", specifier = ">=7.2.0" }, { name = "pkgconfig" }, - { name = "pplpy", specifier = ">=0.8.6" }, - { name = "primecountpy" }, + { name = "platformdirs" }, + { name = "pplpy", marker = "sys_platform != 'win32'", specifier = ">=0.8.6" }, + { name = "primecountpy", marker = "sys_platform != 'win32'" }, { name = "ptyprocess", specifier = ">0.5" }, { name = "requests", specifier = ">=2.13.0" }, { name = "rpy2", marker = "extra == 'r'", specifier = ">=3.3" }, @@ -2236,11 +2341,17 @@ provides-extras = ["r"] dev = [ { name = "conda-lock" }, { name = "grayskull" }, + { name = "meson" }, + { name = "pygithub" }, { name = "toml" }, + { name = "tqdm" }, + { name = "uv" }, ] docs = [ { name = "furo" }, + { name = "python-dateutil" }, { name = "sphinx" }, + { name = "sphinx-copybutton" }, { name = "sphinx-inline-tabs" }, ] lint = [ @@ -2400,6 +2511,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/dd/018ce05c532a22007ac58d4f45232514cd9d6dd0ee1dc374e309db830983/sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b", size = 22496, upload-time = "2023-07-08T18:40:52.659Z" }, ] +[[package]] +name = "sphinx-copybutton" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, +] + [[package]] name = "sphinx-inline-tabs" version = "2023.4.21" @@ -2555,6 +2678,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907, upload-time = "2024-11-22T03:06:36.71Z" }, ] +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + [[package]] name = "traitlets" version = "5.14.3" @@ -2603,6 +2738,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" }, ] +[[package]] +name = "uv" +version = "0.7.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/08/1bcafa9077965de397d927f291827a77a915d75567b42c3ad6bb6a2e0bcd/uv-0.7.13.tar.gz", hash = "sha256:05f3c03c4ea55d294f3da725b6c2c2ff544754c18552da7594def4ec3889dcfb", size = 3308772, upload-time = "2025-06-12T22:23:10.377Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/4e/cdf97c831be960e13c7db28b6ba226e5bdbfee9a38f6099687c7a395ec52/uv-0.7.13-py3-none-linux_armv6l.whl", hash = "sha256:59915aec9fd2b845708a76ddc6c0639cfc99b6e2811854ea2425ee7552aff0e9", size = 17073615, upload-time = "2025-06-12T20:58:46.197Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/27217e8a7a457bc9c068d99f2d860706649130755fa377306d75a326ce0b/uv-0.7.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9c457a84cfbe2019ba301e14edd3e1c950472abd0b87fc77622ab3fc475ba012", size = 17099887, upload-time = "2025-06-12T20:58:50.272Z" }, + { url = "https://files.pythonhosted.org/packages/46/c7/1d7ec2211732512ae43d7176242fea3eea1915c83565953014bbafcb6be2/uv-0.7.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4f828174e15a557d3bc0f809de76135c3b66bcbf524657f8ced9d22fc978b89c", size = 15800953, upload-time = "2025-06-12T20:58:52.897Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5b/81ea6ec50890a064b37d8f8dc097901768f73c747d965ffd96f1ebdfacea/uv-0.7.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:88fcf2bfbb53309531a850af50d2ea75874099b19d4159625d0b4f88c53494b9", size = 16355391, upload-time = "2025-06-12T20:58:55.146Z" }, + { url = "https://files.pythonhosted.org/packages/64/24/92a30049a74bf17c9c4ffbf36462c5ff593617c2d0b78efb3c9d55293746/uv-0.7.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:721b058064150fc1c6d88e277af093d1b4f8bb7a59546fe9969d9ff7dbe3f6fd", size = 16819352, upload-time = "2025-06-12T20:58:57.299Z" }, + { url = "https://files.pythonhosted.org/packages/74/fe/8b4de3addc375ba00bd1a515a79aaccbb3a600bc66c03e5fd159d6928066/uv-0.7.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f28e70baadfebe71dcc2d9505059b988d75e903fc62258b102eb87dc4b6994a3", size = 17518852, upload-time = "2025-06-12T20:58:59.538Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/e9c14c6aba0316da7fe30b0dac4f8f6d1155d0422dcff1138b85f4eb4c08/uv-0.7.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9d2952a1e74c7027347c74cee1cb2be09121a5290db38498b8b17ff585f73748", size = 18405034, upload-time = "2025-06-12T20:59:01.747Z" }, + { url = "https://files.pythonhosted.org/packages/9d/62/a2f4147fa2714ce765104e2984abcdaa0605725b10ca70bee7de4a1ba88c/uv-0.7.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a51006c7574e819308d92a3452b22d5bd45ef8593a4983b5856aa7cb8220885f", size = 18120055, upload-time = "2025-06-12T20:59:03.997Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b2/f4381c1aa4d3d13ff36359e4176cd34d1da1548ba2a6c763a953b282ede0/uv-0.7.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33837aca7bdf02d47554d5d44f9e71756ee17c97073b07b4afead25309855bc7", size = 18283737, upload-time = "2025-06-12T20:59:06.437Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ef/f2e96cec5e4cf65d7fde89b5dcf9540ddacf42e8e39de2fa0332614e55a8/uv-0.7.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5786a29e286f2cc3cbda13a357fd9a4dd5bf1d7448a9d3d842b26b4f784a3a86", size = 17755308, upload-time = "2025-06-12T20:59:08.837Z" }, + { url = "https://files.pythonhosted.org/packages/34/6d/d7a1af8ece6d5cac5287d00e15b9650eb9d3203606add4cd035009d52de6/uv-0.7.13-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:1afdbfcabc3425b383141ba42d413841c0a48b9ee0f4da65459313275e3cea84", size = 16611463, upload-time = "2025-06-12T20:59:10.971Z" }, + { url = "https://files.pythonhosted.org/packages/b4/e8/27294e3067295db8f54dbe8a1f64b6e3000adc1cba29f953c440bc184a5d/uv-0.7.13-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:866cad0d04a7de1aaa3c5cbef203f9d3feef9655972dcccc3283d60122db743b", size = 16759459, upload-time = "2025-06-12T22:22:44.278Z" }, + { url = "https://files.pythonhosted.org/packages/94/6a/36f055eb1b9a44d60eed9a5aa93cf0f23660a19ab07a5ef085331dd9fc0a/uv-0.7.13-py3-none-musllinux_1_1_i686.whl", hash = "sha256:527a12d0c2f4d15f72b275b6f4561ae92af76dd59b4624796fddd45867f13c33", size = 17108780, upload-time = "2025-06-12T22:22:48.412Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/0f09c0de0896d04b4bb81bdd7833643f055e8a5c2c04f8a2ddf3a74453d8/uv-0.7.13-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:4efa555b217e15767f0691a51d435f7bb2b0bf473fdfd59f173aeda8a93b8d17", size = 17900498, upload-time = "2025-06-12T22:22:50.93Z" }, + { url = "https://files.pythonhosted.org/packages/ce/6f/ee435b4ec3903617b5f592c0077ef0c1e22c41e2ab872be2134b223aabb2/uv-0.7.13-py3-none-win32.whl", hash = "sha256:b1af81e57d098b21b28f42ec756f0e26dce2341d59ba4e4f11759bc3ca2c0a99", size = 17329841, upload-time = "2025-06-12T22:22:57.517Z" }, + { url = "https://files.pythonhosted.org/packages/af/05/c16e2b9369d440e3c85439257bd679c3a92bdd248015238a8848941828f6/uv-0.7.13-py3-none-win_amd64.whl", hash = "sha256:8c0c29a2089ff9011d6c3abccd272f3ee6d0e166dae9e5232099fd83d26104d9", size = 18820166, upload-time = "2025-06-12T22:23:05.224Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ac/68fd18d5190515f9ddb31cc2f14e21d1b38bee721ece2d43c42e13646fa3/uv-0.7.13-py3-none-win_arm64.whl", hash = "sha256:e077dcac19e564cae8b4223b7807c2f617a59938f8142ca77fc6348ae9c6d0aa", size = 17456260, upload-time = "2025-06-12T22:23:08.227Z" }, +] + [[package]] name = "virtualenv" version = "20.29.3" @@ -2644,6 +2804,59 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/21/02/88b65cc394961a60c43c70517066b6b679738caf78506a5da7b88ffcb643/widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71", size = 2335872, upload-time = "2024-08-22T12:18:19.491Z" }, ] +[[package]] +name = "wrapt" +version = "1.17.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531, upload-time = "2025-01-14T10:35:45.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/f7/a2aab2cbc7a665efab072344a8949a71081eed1d2f451f7f7d2b966594a2/wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58", size = 53308, upload-time = "2025-01-14T10:33:33.992Z" }, + { url = "https://files.pythonhosted.org/packages/50/ff/149aba8365fdacef52b31a258c4dc1c57c79759c335eff0b3316a2664a64/wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda", size = 38488, upload-time = "2025-01-14T10:33:35.264Z" }, + { url = "https://files.pythonhosted.org/packages/65/46/5a917ce85b5c3b490d35c02bf71aedaa9f2f63f2d15d9949cc4ba56e8ba9/wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438", size = 38776, upload-time = "2025-01-14T10:33:38.28Z" }, + { url = "https://files.pythonhosted.org/packages/ca/74/336c918d2915a4943501c77566db41d1bd6e9f4dbc317f356b9a244dfe83/wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a", size = 83776, upload-time = "2025-01-14T10:33:40.678Z" }, + { url = "https://files.pythonhosted.org/packages/09/99/c0c844a5ccde0fe5761d4305485297f91d67cf2a1a824c5f282e661ec7ff/wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000", size = 75420, upload-time = "2025-01-14T10:33:41.868Z" }, + { url = "https://files.pythonhosted.org/packages/b4/b0/9fc566b0fe08b282c850063591a756057c3247b2362b9286429ec5bf1721/wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6", size = 83199, upload-time = "2025-01-14T10:33:43.598Z" }, + { url = "https://files.pythonhosted.org/packages/9d/4b/71996e62d543b0a0bd95dda485219856def3347e3e9380cc0d6cf10cfb2f/wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b", size = 82307, upload-time = "2025-01-14T10:33:48.499Z" }, + { url = "https://files.pythonhosted.org/packages/39/35/0282c0d8789c0dc9bcc738911776c762a701f95cfe113fb8f0b40e45c2b9/wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662", size = 75025, upload-time = "2025-01-14T10:33:51.191Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6d/90c9fd2c3c6fee181feecb620d95105370198b6b98a0770cba090441a828/wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72", size = 81879, upload-time = "2025-01-14T10:33:52.328Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fa/9fb6e594f2ce03ef03eddbdb5f4f90acb1452221a5351116c7c4708ac865/wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317", size = 36419, upload-time = "2025-01-14T10:33:53.551Z" }, + { url = "https://files.pythonhosted.org/packages/47/f8/fb1773491a253cbc123c5d5dc15c86041f746ed30416535f2a8df1f4a392/wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3", size = 38773, upload-time = "2025-01-14T10:33:56.323Z" }, + { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799, upload-time = "2025-01-14T10:33:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821, upload-time = "2025-01-14T10:33:59.334Z" }, + { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919, upload-time = "2025-01-14T10:34:04.093Z" }, + { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721, upload-time = "2025-01-14T10:34:07.163Z" }, + { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899, upload-time = "2025-01-14T10:34:09.82Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222, upload-time = "2025-01-14T10:34:11.258Z" }, + { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707, upload-time = "2025-01-14T10:34:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685, upload-time = "2025-01-14T10:34:15.043Z" }, + { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567, upload-time = "2025-01-14T10:34:16.563Z" }, + { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672, upload-time = "2025-01-14T10:34:17.727Z" }, + { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865, upload-time = "2025-01-14T10:34:19.577Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b9/0ffd557a92f3b11d4c5d5e0c5e4ad057bd9eb8586615cdaf901409920b14/wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", size = 53800, upload-time = "2025-01-14T10:34:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ef/8be90a0b7e73c32e550c73cfb2fa09db62234227ece47b0e80a05073b375/wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", size = 38824, upload-time = "2025-01-14T10:34:22.999Z" }, + { url = "https://files.pythonhosted.org/packages/36/89/0aae34c10fe524cce30fe5fc433210376bce94cf74d05b0d68344c8ba46e/wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", size = 38920, upload-time = "2025-01-14T10:34:25.386Z" }, + { url = "https://files.pythonhosted.org/packages/3b/24/11c4510de906d77e0cfb5197f1b1445d4fec42c9a39ea853d482698ac681/wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", size = 88690, upload-time = "2025-01-14T10:34:28.058Z" }, + { url = "https://files.pythonhosted.org/packages/71/d7/cfcf842291267bf455b3e266c0c29dcb675b5540ee8b50ba1699abf3af45/wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", size = 80861, upload-time = "2025-01-14T10:34:29.167Z" }, + { url = "https://files.pythonhosted.org/packages/d5/66/5d973e9f3e7370fd686fb47a9af3319418ed925c27d72ce16b791231576d/wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", size = 89174, upload-time = "2025-01-14T10:34:31.702Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d3/8e17bb70f6ae25dabc1aaf990f86824e4fd98ee9cadf197054e068500d27/wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", size = 86721, upload-time = "2025-01-14T10:34:32.91Z" }, + { url = "https://files.pythonhosted.org/packages/6f/54/f170dfb278fe1c30d0ff864513cff526d624ab8de3254b20abb9cffedc24/wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", size = 79763, upload-time = "2025-01-14T10:34:34.903Z" }, + { url = "https://files.pythonhosted.org/packages/4a/98/de07243751f1c4a9b15c76019250210dd3486ce098c3d80d5f729cba029c/wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", size = 87585, upload-time = "2025-01-14T10:34:36.13Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f0/13925f4bd6548013038cdeb11ee2cbd4e37c30f8bfd5db9e5a2a370d6e20/wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", size = 36676, upload-time = "2025-01-14T10:34:37.962Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ae/743f16ef8c2e3628df3ddfd652b7d4c555d12c84b53f3d8218498f4ade9b/wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", size = 38871, upload-time = "2025-01-14T10:34:39.13Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bc/30f903f891a82d402ffb5fda27ec1d621cc97cb74c16fea0b6141f1d4e87/wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", size = 56312, upload-time = "2025-01-14T10:34:40.604Z" }, + { url = "https://files.pythonhosted.org/packages/8a/04/c97273eb491b5f1c918857cd26f314b74fc9b29224521f5b83f872253725/wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", size = 40062, upload-time = "2025-01-14T10:34:45.011Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ca/3b7afa1eae3a9e7fefe499db9b96813f41828b9fdb016ee836c4c379dadb/wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", size = 40155, upload-time = "2025-01-14T10:34:47.25Z" }, + { url = "https://files.pythonhosted.org/packages/89/be/7c1baed43290775cb9030c774bc53c860db140397047cc49aedaf0a15477/wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", size = 113471, upload-time = "2025-01-14T10:34:50.934Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/4ed894cf012b6d6aae5f5cc974006bdeb92f0241775addad3f8cd6ab71c8/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", size = 101208, upload-time = "2025-01-14T10:34:52.297Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fd/0c30f2301ca94e655e5e057012e83284ce8c545df7661a78d8bfca2fac7a/wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", size = 109339, upload-time = "2025-01-14T10:34:53.489Z" }, + { url = "https://files.pythonhosted.org/packages/75/56/05d000de894c4cfcb84bcd6b1df6214297b8089a7bd324c21a4765e49b14/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", size = 110232, upload-time = "2025-01-14T10:34:55.327Z" }, + { url = "https://files.pythonhosted.org/packages/53/f8/c3f6b2cf9b9277fb0813418e1503e68414cd036b3b099c823379c9575e6d/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", size = 100476, upload-time = "2025-01-14T10:34:58.055Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b1/0bb11e29aa5139d90b770ebbfa167267b1fc548d2302c30c8f7572851738/wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", size = 106377, upload-time = "2025-01-14T10:34:59.3Z" }, + { url = "https://files.pythonhosted.org/packages/6a/e1/0122853035b40b3f333bbb25f1939fc1045e21dd518f7f0922b60c156f7c/wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", size = 37986, upload-time = "2025-01-14T10:35:00.498Z" }, + { url = "https://files.pythonhosted.org/packages/09/5e/1655cf481e079c1f22d0cabdd4e51733679932718dc23bf2db175f329b76/wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", size = 40750, upload-time = "2025-01-14T10:35:03.378Z" }, + { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, +] + [[package]] name = "zipp" version = "3.21.0" From 85a4b8d4fffe97004e8d028c5362bc30dd88cd60 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 23 Jun 2025 13:48:47 +0200 Subject: [PATCH 21/21] Fix typo in meson install instructions --- src/doc/en/installation/meson.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/installation/meson.rst b/src/doc/en/installation/meson.rst index 01a05675b3a..0f3d70f387e 100644 --- a/src/doc/en/installation/meson.rst +++ b/src/doc/en/installation/meson.rst @@ -172,7 +172,7 @@ To compile and install Sage in editable install, then just use: memory_allocator \ "numpy >=1.25" \ jinja2 \ - setuptool + setuptools $ uv sync --frozen --inexact --no-build-isolation You can then start Sage from the command line with ``./sage``