diff --git a/.backportrc.json b/.backportrc.json deleted file mode 100644 index 72c9b85b..00000000 --- a/.backportrc.json +++ /dev/null @@ -1,16 +0,0 @@ -// .backportrc.json -- for https://github.com/sorenlouv/backport -{ - // Required - "repoOwner": "mpmath", - "repoName": "mpmath", - // the branches available to backport to - "targetBranchChoices": ["mpmath-1.4.x"], - // Automatically detect which branches a pull request should be - // backported to based on the pull request labels. - "branchLabelMapping": { - "^backport-to-(.+)$": "mpmath-$1" - }, - "targetPRLabels": ["backport"], - "sourcePRLabels": ["backport-pr-created"], - "commitConflicts": true -} diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml deleted file mode 100644 index 56d58396..00000000 --- a/.github/workflows/backport.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Automatic backport action - -on: - pull_request_target: - types: ["labeled", "closed"] - -permissions: - contents: write # so it can comment - pull-requests: write # so it can create pull requests - -jobs: - backport: - name: Backport PR - if: github.event.pull_request.merged == true && !(contains(github.event.pull_request.labels.*.name, 'backport')) && !(contains(github.event.pull_request.labels.*.name, 'backport-pr-created')) - runs-on: ubuntu-24.04 - steps: - # Workaround not to fail the workflow if the PR does not need a backport - # https://github.com/sorenlouv/backport-github-action/issues/127#issuecomment-2277248320 - - name: Check for backport labels - id: check_labels - run: |- - labels='${{ toJSON(github.event.pull_request.labels.*.name) }}' - matched=$(echo "${labels}" | jq '. | map(select(startswith("backport-to-"))) | length') - echo "matched=$matched" - echo "matched=$matched" >> $GITHUB_OUTPUT - - name: Backport Action - if: fromJSON(steps.check_labels.outputs.matched) > 0 - uses: sorenlouv/backport-github-action@v10.2.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - auto_backport_label_prefix: backport-to- - - name: Info log - if: ${{ success() && fromJSON(steps.check_labels.outputs.matched) > 0 }} - run: cat ~/.backport/backport.info.log - - name: Debug log - if: ${{ failure() && fromJSON(steps.check_labels.outputs.matched) > 0 }} - run: cat ~/.backport/backport.debug.log diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb0acdf1..871f9bea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,10 +12,22 @@ jobs: uses: ./.github/workflows/coverage.yml docs: uses: ./.github/workflows/docs.yml + frozen-version: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: actions/setup-python@v6 + with: + python-version: "3.x" + - name: Run frozen version test + run: bash mpmath/tests/test_version_frozen.sh tests: needs: - linter - coverage + - frozen-version runs-on: ubuntu-24.04 strategy: fail-fast: false diff --git a/.gitignore b/.gitignore index 2d6f0479..32835e1e 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ my/ dist/ build/ +# Generated by setuptools_scm +mpmath/_version.py + # Tox files .tox/ diff --git a/CHANGES b/CHANGES index 68bffd1c..589a16f5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,14 @@ +--1.4.1-- +Released March 15, 2026 + +Bug fixes: + +* Fix test_hexadecimal_with_libc_bulk(), see #1049 (Doug Torrance) +* Keep available deprecated aliases for mpc/mpf_log() (Sergey B Kirpichev) +* Use version_file option of setuptools-scm to keep version info, see #1048 + (Sergey B Kirpichev) +* Add workaround for test on s390x, see #1061 (Sergey B Kirpichev) + --1.4.0-- Released February 23, 2026 diff --git a/mpmath/__init__.py b/mpmath/__init__.py index c8672988..2318f7b8 100644 --- a/mpmath/__init__.py +++ b/mpmath/__init__.py @@ -1,7 +1,4 @@ -from importlib.metadata import version - -__version__ = version(__name__) -del version +from ._version import __version__ import functools import sys diff --git a/mpmath/libmp/libelefun.py b/mpmath/libmp/libelefun.py index 0c16c0ce..03de1bbb 100644 --- a/mpmath/libmp/libelefun.py +++ b/mpmath/libmp/libelefun.py @@ -737,10 +737,7 @@ def mpf_ln(x, prec, rnd=round_fast): m -= n*ln2_fixed(wp) return from_man_exp(m, -wp, prec, rnd) -def mpf_log(x, prec, rnd=round_fast): - warnings.warn("mpf_log is deprecated, use mpf_ln", - DeprecationWarning) - return mpf_ln(x, prec, rnd) +mpf_log = mpf_ln # deprecated alias def mpf_log1p(x, prec, rnd=round_fast): """ diff --git a/mpmath/libmp/libmpc.py b/mpmath/libmp/libmpc.py index e19cf0d1..c063e001 100644 --- a/mpmath/libmp/libmpc.py +++ b/mpmath/libmp/libmpc.py @@ -3,7 +3,6 @@ Low-level functions for complex arithmetic. """ import sys -import warnings from .backend import MPZ from .libelefun import (mpf_acos, mpf_acosh, mpf_asin, mpf_atan, mpf_atan2, @@ -436,10 +435,7 @@ def mpc_ln(z, prec, rnd=round_fast): im = mpc_arg(z, prec, rnd) return re, im -def mpc_log(x, prec, rnd=round_fast): - warnings.warn("mpc_log is deprecated, use mpc_ln", - DeprecationWarning) - return mpc_ln(x, prec, rnd) +mpc_log = mpc_ln # deprecated alias def mpc_cos(z, prec, rnd=round_fast): """Complex cosine. The formula used is cos(a+bi) = cos(a)*cosh(b) - diff --git a/mpmath/libmp/libmpf.py b/mpmath/libmp/libmpf.py index 4e652b5f..00c8d984 100644 --- a/mpmath/libmp/libmpf.py +++ b/mpmath/libmp/libmpf.py @@ -1102,12 +1102,10 @@ def to_digits_exp(s, dps, base=10): return sign, digits, exponent def round_digits(sign, digits, dps, base, rnd=round_nearest, fixed=False): - ''' + """ Returns the rounded digits, and the number of places the decimal point was shifted. - - Supports three kinds of rounding: up, down, or nearest. - ''' + """ assert len(digits) > dps assert rnd in (round_nearest, round_up, round_down, round_ceiling, diff --git a/mpmath/tests/test_basic_ops.py b/mpmath/tests/test_basic_ops.py index afc6efc0..c98c1802 100644 --- a/mpmath/tests/test_basic_ops.py +++ b/mpmath/tests/test_basic_ops.py @@ -707,13 +707,6 @@ def test_issue_985(): assert mpc(-1) in {1, -1} -def test_mpfmpc_log_deprecation(): - with pytest.deprecated_call(): - mpmath.libmp.mpf_log(mpf(123)._mpf_, 53) - with pytest.deprecated_call(): - mpmath.libmp.mpc_log(mpc(123)._mpc_, 53) - - def test_issue_975(): def worker(): mp = mpmath.MPContext() diff --git a/mpmath/tests/test_format.py b/mpmath/tests/test_format.py index 00ac61f2..896c003c 100644 --- a/mpmath/tests/test_format.py +++ b/mpmath/tests/test_format.py @@ -864,6 +864,7 @@ except OSError: def float_print(d, i): fmt = "%." + str(i) + "a\n" a = ctypes.create_string_buffer(256) + libc.sprintf.argtypes = [ctypes.c_char_p, ctypes.c_char_p] libc.sprintf(a, bytes(fmt, 'utf-8'), ctypes.c_double(d)) return a.raw.decode('utf-8').split("\n")[0] diff --git a/mpmath/tests/test_functions2.py b/mpmath/tests/test_functions2.py index a7db90a8..47fcbf68 100644 --- a/mpmath/tests/test_functions2.py +++ b/mpmath/tests/test_functions2.py @@ -1,3 +1,5 @@ +import platform + import pytest from mpmath import (agm, airyai, airybi, appellf1, bei, ber, besseli, besselj, @@ -1470,7 +1472,13 @@ def test_issue_239(): x = ldexp(2476979795053773,-52) assert betainc(206, 385, 0, 0.55, 1).ae('0.99999999999999999999996570910644857895771110649954') mp.dps = 15 - pytest.raises(ValueError, lambda: hyp2f1(-5,5,0.5,0.5)) + expected_exc = ValueError + if platform.machine() == 's390x': + # This case has recursion depth beyond platform capabilities, that + # could be controlled with sys.setrecursionlimit(). See issue #1046 + # for details. + expected_exc = RecursionError + pytest.raises(expected_exc, lambda: hyp2f1(-5,5,0.5,0.5)) # Extra stress testing for Bessel functions # Reference zeros generated with the aid of scipy.special diff --git a/mpmath/tests/test_version_frozen.sh b/mpmath/tests/test_version_frozen.sh new file mode 100644 index 00000000..69dc546b --- /dev/null +++ b/mpmath/tests/test_version_frozen.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Test that the version number is provided correctly in a frozen (bundled) +# executable (see #1044). + +set -e + +# Get the directory of the current repository +MPMATH_DIR="$(realpath "$(dirname "$0")/../../")" +echo "Repo mpmath directory: $MPMATH_DIR" + +echo "Install requirements..." +python3 -m pip install build pyinstaller + +echo "Building the source distribution from the local repo..." +python3 -m build --sdist + +# Find and install the generated tarball +TARBALL=$(ls -t dist/*.tar.gz | head -1) +echo "Generated tarball: $TARBALL" + +echo "Installing mpmath from tarball..." +pip install dist/"$(basename $TARBALL)" + +TEMP_DIR=$(mktemp -d) +echo "Created temporary directory: $TEMP_DIR" +cd "$TEMP_DIR" + +# Create version_script.py that prints the package version +cat << EOF > version_script.py +import mpmath +print(mpmath.__version__) +EOF + +# Save local version for later comparison +DIRECT_VERSION="$(python3 -m mpmath --version)" + +echo "Building version_script with PyInstaller..." +pyinstaller --onefile --clean version_script.py + +echo "Run frozen executable and extract the version from the output..." +FROZEN_VERSION="$(./dist/version_script 2>&1)" + +if [ "$DIRECT_VERSION" == "$FROZEN_VERSION" ]; then + echo "Test passed: Version matches in frozen (bundled) executable." +else + echo "Test failed: Version mismatch." + echo "Direct version: $DIRECT_VERSION" + echo "Frozen version: $FROZEN_VERSION" + exit 1 +fi diff --git a/pyproject.toml b/pyproject.toml index 71f0f943..6f688aac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ exclude = ['.eggs', '.git'] max_line_length = 200 [tool.setuptools_scm] +version_file = "mpmath/_version.py" [tool.pytest.ini_options] testpaths = ['mpmath', 'docs'] @@ -66,7 +67,7 @@ timeout = 600 [tool.coverage.run] branch = true -omit = ['mpmath/tests/*'] +omit = ['mpmath/tests/*', 'mpmath/_version.py'] patch = ["subprocess"] [tool.coverage.html]