From 1849493abcd1231647a878ecd8be373ebd038f39 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 Dec 2023 12:31:24 -0800 Subject: [PATCH] WIP --- .github/workflows/build.yml | 80 +----------------------- .github/workflows/ci-conda.yml | 104 -------------------------------- src/bin/sage-runtests | 2 + src/sage/combinat/words/word.py | 4 +- src/sage/doctest/control.py | 1 + src/sage/doctest/forker.py | 47 ++++++++++++--- src/sage_setup/clean.py | 2 +- 7 files changed, 45 insertions(+), 195 deletions(-) delete mode 100644 .github/workflows/ci-conda.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c9282086422..82c2f19dc8f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -96,39 +96,6 @@ jobs: MAKE: make -j2 --output-sync=recurse SAGE_NUM_THREADS: 2 - - name: Build modularized distributions - if: (success() || failure()) && steps.worktree.outcome == 'success' - run: make V=0 tox && make SAGE_CHECK=no pypi-wheels - working-directory: ./worktree-image - env: - MAKE: make -j2 --output-sync=recurse - SAGE_NUM_THREADS: 2 - - - name: Static code check with pyright - if: (success() || failure()) && steps.worktree.outcome == 'success' - uses: jakebailey/pyright-action@v1 - with: - version: 1.1.332 - # Many warnings issued by pyright are not yet helpful because there is not yet enough type information. - no-comments: true - working-directory: ./worktree-image - env: - # To avoid out of memory errors - NODE_OPTIONS: --max-old-space-size=8192 - - - name: Static code check with pyright (annotated) - if: (success() || failure()) && steps.worktree.outcome == 'success' - uses: jakebailey/pyright-action@v1 - with: - version: 1.1.332 - # Issue errors - no-comments: false - level: error - working-directory: ./worktree-image - env: - # To avoid out of memory errors - NODE_OPTIONS: --max-old-space-size=8192 - - name: Clean (fallback to non-incremental) id: clean if: (success() || failure()) && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' @@ -154,52 +121,9 @@ jobs: # Testing - - name: Test changed files (sage -t --new) - if: (success() || failure()) && steps.build.outcome == 'success' - run: | - # We run tests with "sage -t --new"; this only tests the uncommitted changes. - ./sage -t --new -p2 - working-directory: ./worktree-image - env: - MAKE: make -j2 --output-sync=recurse - SAGE_NUM_THREADS: 2 - - - name: Test modularized distributions - if: (success() || failure()) && steps.build.outcome == 'success' - run: make V=0 tox && make pypi-wheels-check - working-directory: ./worktree-image - env: - MAKE: make -j2 --output-sync=recurse - SAGE_NUM_THREADS: 2 - - - name: Pytest - if: contains(github.ref, 'pytest') - run: | - ../sage -python -m pip install coverage pytest-xdist - ../sage -python -m coverage run -m pytest -c tox.ini --doctest-modules || true - working-directory: ./worktree-image/src - env: - # Increase the length of the lines in the "short summary" - COLUMNS: 120 - - name: Test all files (sage -t --all --long) if: (success() || failure()) && steps.build.outcome == 'success' run: | - ../sage -python -m pip install coverage - ../sage -python -m coverage run ./bin/sage-runtests --all --long -p2 --random-seed=286735480429121101562228604801325644303 - working-directory: ./worktree-image/src - - - name: Prepare coverage results - if: (success() || failure()) && steps.build.outcome == 'success' - run: | - ./venv/bin/python3 -m coverage combine src/.coverage/ - ./venv/bin/python3 -m coverage xml - mkdir -p coverage-report - mv coverage.xml coverage-report/ + ./sage -python -m pip install coverage + ./sage -python -m coverage run ./src/bin/sage-runtests --format github --baseline-stats-path=.github/workflows/ci-conda-known-test-failures.json -p4 --random-seed=286735480429121101562228604801325644303 src/sage/combinat/words src/sage/plot/plot.py src/sage_setup/clean.py working-directory: ./worktree-image - - - name: Upload coverage to codecov - if: (success() || failure()) && steps.build.outcome == 'success' - uses: codecov/codecov-action@v3 - with: - directory: ./worktree-image/coverage-report diff --git a/.github/workflows/ci-conda.yml b/.github/workflows/ci-conda.yml deleted file mode 100644 index 6432b7a0a6a..00000000000 --- a/.github/workflows/ci-conda.yml +++ /dev/null @@ -1,104 +0,0 @@ -name: Build & Test using Conda - -on: - push: - tags: - - '*' - branches: - - 'public/build/**-runci' - pull_request: - workflow_dispatch: - # Allow to run manually - -concurrency: - # Cancel previous runs of this workflow for the same branch - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - test: - name: Conda - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - python: ['3.9', '3.10', '3.11'] - # Optional environment is disabled for now as its not yet working - # environment: [environment, environment-optional] - conda-env: [environment] - - steps: - - uses: actions/checkout@v4 - - - name: Merge CI fixes from sagemath/sage - run: | - .ci/merge-fixes.sh - env: - GH_TOKEN: ${{ github.token }} - SAGE_CI_FIXES_FROM_REPOSITORIES: ${{ vars.SAGE_CI_FIXES_FROM_REPOSITORIES }} - - - name: Create conda environment files - run: ./bootstrap-conda - - - name: Cache conda packages - uses: actions/cache@v3 - with: - path: ~/conda_pkgs_dir - key: - ${{ runner.os }}-conda-${{ hashFiles('src/environment-3.11.yml') }} - - - name: Setup Conda environment - uses: conda-incubator/setup-miniconda@v2 - with: - python-version: ${{ matrix.python }} - miniforge-version: latest - use-mamba: true - channels: conda-forge - channel-priority: true - activate-environment: sage - environment-file: src/${{ matrix.conda-env }}-${{ matrix.python }}.yml - - - name: Print Conda environment - shell: bash -l {0} - run: | - conda info - conda list - - - name: Configure - shell: bash -l {0} - continue-on-error: true - run: | - ./bootstrap - echo "::add-matcher::.github/workflows/configure-systempackage-problem-matcher.json" - ./configure --enable-build-as-root --with-python=$CONDA_PREFIX/bin/python --prefix=$CONDA_PREFIX --enable-system-site-packages $(for pkg in $(./sage -package list :standard: --has-file spkg-configure.m4 --has-file distros/conda.txt --exclude rpy2); do echo --with-system-$pkg=force; done) - echo "::remove-matcher owner=configure-system-package-warning::" - echo "::remove-matcher owner=configure-system-package-error::" - - - name: Build - shell: bash -l {0} - run: | - # Use --no-deps and pip check below to verify that all necessary dependencies are installed via conda. - pip install --no-build-isolation --no-deps -v -v -e ./pkgs/sage-conf ./pkgs/sage-setup - pip install --no-build-isolation --no-deps --config-settings editable_mode=compat -v -v -e ./src - env: - SAGE_NUM_THREADS: 2 - - - name: Verify dependencies - if: success() || failure() - shell: bash -l {0} - run: pip check - - - name: Test - if: success() || failure() - shell: bash -l {0} - run: ./sage -t --all --baseline-stats-path=.github/workflows/ci-conda-known-test-failures.json -p0 - - - name: Print logs - if: always() - run: | - for file in $(find . -type f -name "*.log"); do - echo "::group::$file" - cat "$file" - echo "::endgroup::" - done diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index e25cebb48a8..25444933bf6 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -34,6 +34,8 @@ if __name__ == "__main__": what.add_argument("--installed", action="store_true", default=False, help="test all installed modules of the Sage library") parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE") + parser.add_argument("--format", choices=["sage", "github"], default="sage", + help="set format of error messages and warnings") parser.add_argument("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', type=int, default=-1, const=300, metavar="SECONDS", diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 132195589e9..240e66b6a24 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -148,7 +148,7 @@ def Word(data=None, alphabet=None, length=None, datatype=None, caching=True, RSK Word over a string with a parent:: - sage: w = Word("abbabaab", alphabet="abc"); w + sage: w = Word("abbabaab", daslkdlsakdlksaldkasldklsakdlsak, alphabet="abc"); w word: abbabaab sage: w.parent() Finite words over {'a', 'b', 'c'} @@ -253,7 +253,7 @@ class FiniteWord_char(WordDatatype_char, FiniteWord_class): True sage: w.is_square_free() - False + Falsish sage: w[:-1].is_square_free() True diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 37562e1717c..01a9e080384 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -139,6 +139,7 @@ def __init__(self, **kwds): self.show_skipped = False self.target_walltime = -1 self.baseline_stats_path = None + self.format = "sage" # sage-runtests contains more optional tags. Technically, adding # auto_optional_tags here is redundant, since that is added diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index cb8348e2732..a6b43b37aa2 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -1235,16 +1235,40 @@ def _failure_header(self, test, example, message='Failed example:'): """ out = [self.DIVIDER] with OriginalSource(example): - if test.filename: - if test.lineno is not None and example.lineno is not None: - lineno = test.lineno + example.lineno + 1 - else: - lineno = '?' - out.append('File "%s", line %s, in %s' % - (test.filename, lineno, test.name)) - else: - out.append('Line %s, in %s' % (example.lineno + 1, test.name)) - out.append(message) + match self.options.format: + case 'sage': + if test.filename: + if test.lineno is not None and example.lineno is not None: + lineno = test.lineno + example.lineno + 1 + else: + lineno = '?' + out.append('File "%s", line %s, in %s' % + (test.filename, lineno, test.name)) + else: + out.append('Line %s, in %s' % (example.lineno + 1, test.name)) + out.append(message) + case 'github': + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions + if message.startswith('Warning: '): + command = f'::warning title={message}' + message = message[len('Warning: '):] + elif self.baseline.get('failed', False): + command = f'::notice title={message}' + message += ' [failed in baseline]' + else: + command = f'::error title={message}' + if extra := getattr(example, 'extra', None): + message += f': {extra}' + if test.filename: + command += f',file={test.filename}' + if test.lineno is not None and example.lineno is not None: + lineno = test.lineno + example.lineno + 1 + command += f',line={lineno}' + lineno = None + else: + command += f',line={example.lineno + 1}' + command += f'::{message}' + out.append(command) source = example.source out.append(doctest._indent(source)) return '\n'.join(out) @@ -1417,6 +1441,7 @@ def report_failure(self, out, test, example, got, globs): """ if not self.options.initial or self.no_failure_yet: self.no_failure_yet = False + example.extra = f'Got: {got!r}' returnval = doctest.DocTestRunner.report_failure(self, out, test, example, got) if self.options.debug: self._fakeout.stop_spoofing() @@ -1567,6 +1592,8 @@ def report_unexpected_exception(self, out, test, example, exc_info): """ if not self.options.initial or self.no_failure_yet: self.no_failure_yet = False + + example.extra = "Exception raised: " + repr("".join(traceback.format_exception(*exc_info))) returnval = doctest.DocTestRunner.report_unexpected_exception(self, out, test, example, exc_info) if self.options.debug: self._fakeout.stop_spoofing() diff --git a/src/sage_setup/clean.py b/src/sage_setup/clean.py index e9c81c9ed1a..bac2ed26417 100644 --- a/src/sage_setup/clean.py +++ b/src/sage_setup/clean.py @@ -101,7 +101,7 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module sage: stale_iter = _find_stale_files(SAGE_LIB, python_packages, python_modules, [], extra_files) sage: from importlib.machinery import EXTENSION_SUFFIXES sage: skip_extensions = tuple(EXTENSION_SUFFIXES) - sage: for f in stale_iter: + sage: for f in stale_iter:dxfcgvhbjkl;,mkjnbhgvcfgvhbjnkml, ....: if f.endswith(skip_extensions): continue ....: if '/ext_data/' in f: continue ....: print('Found stale file: ' + f)