Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
29c876b
Support ints in benchmarks
skirpichev Feb 11, 2026
136899c
Relax default timeout more (for PyPy)
skirpichev Feb 14, 2026
450cba4
Bump actions/download-artifact from 7 to 8
dependabot[bot] Mar 1, 2026
740d71e
Bump actions/upload-artifact from 6 to 7
dependabot[bot] Mar 1, 2026
dab05d3
Improve dependabot settings
skirpichev Mar 2, 2026
108dfc9
Polish pytest_report_header()
skirpichev Mar 28, 2026
22e97ea
Use new runner images for MacOS/Windows
skirpichev Mar 28, 2026
eaadfa0
Refactor benchmarks, add sum and harmonic
skirpichev Mar 28, 2026
4d1a8c9
Update msys2/setup-msys2 action
skirpichev Mar 28, 2026
b65c473
Amend 20b33d8
skirpichev Mar 29, 2026
6421b14
Bump the actions-deps group with 4 updates
dependabot[bot] Apr 1, 2026
5835422
Drop most workarounds for PyPy3.11
skirpichev Apr 3, 2026
9cc1649
Update pypa/cibuildwheel to v3.4.1
skirpichev Apr 3, 2026
46d87c1
Test types, returned by mpmath.libmp.libmpf.*
skirpichev Apr 3, 2026
b9bb045
Drop some workaround for oracle/graalpython#534
skirpichev Apr 3, 2026
0d79cc3
Bump msys2/setup-msys2 from 2.31.0 to 2.31.1 in the actions-deps group
dependabot[bot] May 1, 2026
297a06e
Bump sorenlouv/backport-github-action in the actions-deps group
dependabot[bot] Jun 2, 2026
ffc47e8
Use pypa/cibuildwheel v4.0.0
skirpichev Jun 8, 2026
ec33b31
Remove workarounds for PyPy
skirpichev Jun 8, 2026
3a0d457
Use j178/prek-action
skirpichev Jun 9, 2026
a38b4a0
Support CPython v3.15
skirpichev Jun 20, 2026
0f8fd61
Update PyPy/GraalPy versions in the README.rst
skirpichev Jun 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ updates:
directory: "/"
schedule:
interval: "monthly"
rebase-strategy: "disabled"
groups:
actions-deps:
patterns:
- "*"
2 changes: 1 addition & 1 deletion .github/workflows/backport.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
echo "matched=$matched" >> $GITHUB_OUTPUT
- name: Backport Action
if: fromJSON(steps.check_labels.outputs.matched) > 0
uses: sorenlouv/backport-github-action@v10.2.0
uses: sorenlouv/backport-github-action@v12.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
auto_backport_label_prefix: backport-to-
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
lcov --remove coverage.info "*.h" --ignore-errors unused \
--output-file coverage.info
cp coverage.info build/coverage-${{ matrix.python-version }}.info
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: coverage-${{ matrix.python-version }}
path: |
Expand All @@ -64,7 +64,7 @@ jobs:
fetch-depth: 0
- run: sudo apt-get update
- run: sudo apt-get install lcov diff-cover
- uses: actions/download-artifact@v7
- uses: actions/download-artifact@v8
with:
pattern: coverage-*
path: build/
Expand All @@ -75,13 +75,13 @@ jobs:
- run: |
diff-cover build/coverage*.info --fail-under=100 \
--compare-branch=origin/master
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: coverage
path: |
build/coverage/
build/coverage*.info
- uses: codecov/codecov-action@v5
- uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
gcov_ignore: pythoncapi_compat.h
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- uses: pre-commit/action@v3.0.1
- uses: j178/prek-action@v2
8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- run: python -m build -s
env:
PKG_CONFIG_PATH: ${{ github.workspace }}/.local/lib/pkgconfig
- uses: actions/upload-artifact@v6
- uses: actions/upload-artifact@v7
with:
name: python-gmp-sdist
path: dist/
Expand All @@ -45,7 +45,7 @@ jobs:
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v7
- uses: actions/download-artifact@v8
with:
pattern: python-gmp-*
path: dist/
Expand All @@ -62,12 +62,12 @@ jobs:
contents: write
id-token: write
steps:
- uses: actions/download-artifact@v7
- uses: actions/download-artifact@v8
with:
pattern: python-gmp-*
path: dist/
merge-multiple: true
- uses: sigstore/gh-action-sigstore-python@v3.2.0
- uses: sigstore/gh-action-sigstore-python@v3.3.0
with:
inputs: >-
./dist/*.tar.gz
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-15,
windows-2022]
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-26-intel, macos-26,
windows-2025-vs2026]
msystem: [ucrt64]
menv: [ucrt-x86_64]
include:
Expand All @@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: msys2/setup-msys2@v2.30.0
- uses: msys2/setup-msys2@v2.31.1
name: Setup msys2
with:
install: >-
Expand All @@ -42,8 +42,8 @@ jobs:
- run: echo "PKG_CONFIG_PATH=${{ github.workspace }}/.local/lib/pkgconfig" >> $env:GITHUB_ENV
if: ${{ startsWith(matrix.os, 'windows') }}
- name: Build wheels
uses: pypa/cibuildwheel@v3.3.1
- uses: actions/upload-artifact@v6
uses: pypa/cibuildwheel@v4.0.0
- uses: actions/upload-artifact@v7
with:
name: wheels-${{ matrix.os }}
path: ./wheelhouse/
Expand All @@ -52,7 +52,7 @@ jobs:
needs: build_wheels
steps:
- name: Merge Wheels
uses: actions/upload-artifact/merge@v6
uses: actions/upload-artifact/merge@v7
with:
name: python-gmp-wheels
pattern: wheels-*
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ functions, compatible with the Python stdlib's submodule `math.integer
<https://docs.python.org/3.15/library/math.integer.html>`_.

This module requires Python 3.11 or later versions and has been tested with
CPython 3.11 through 3.14, with PyPy3.11 7.3.20 and with GraalPy 25.0.
CPython 3.11 through 3.15, with PyPy3.11 7.3.23 and with GraalPy 25.0.3.
Free-threading builds of the CPython are supported.

Releases are available in the Python Package Index (PyPI) at
Expand Down
1 change: 1 addition & 0 deletions bench/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ It's possible to run them also with gmpy2's and flint's integer types:
.. code:: sh

( export T="gmpy2.mpz"; \
export PYTHONPATH=. ; \
python bench/mul.py -q --copy-env --rigorous -o $T.json )

Beware, that the gmp prefers clang over gcc and extensions might
Expand Down
11 changes: 2 additions & 9 deletions bench/collatz.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
# collatz.py

import os
# bench/collatz.py

import pyperf

if os.getenv("T") == "gmpy2.mpz":
from gmpy2 import mpz
elif os.getenv("T") == "flint.fmpz":
from flint import fmpz as mpz
else:
from gmp import mpz
from bench.utils import mpz

zero = mpz(0)
one = mpz(1)
Expand Down
12 changes: 12 additions & 0 deletions bench/harmonic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# bench/harmonic.py

from fractions import Fraction

import pyperf

from bench.utils import mpz, mysum

runner = pyperf.Runner()
for n in [100, 1000]:
xs = [Fraction(mpz(1), mpz(i)) for i in range(1, n + 1)]
runner.bench_func(f"H({n})", mysum, xs)
10 changes: 2 additions & 8 deletions bench/mul.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
# mul.py
# bench/mul.py

import os
from operator import mul

import pyperf

if os.getenv("T") == "gmpy2.mpz":
from gmpy2 import mpz
elif os.getenv("T") == "flint.fmpz":
from flint import fmpz as mpz
else:
from gmp import mpz
from bench.utils import mpz

values = ["1<<7", "1<<38", "1<<300", "1<<3000"]

Expand Down
10 changes: 10 additions & 0 deletions bench/sum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# bench/sum.py

import pyperf

from bench.utils import mpz, mysum

runner = pyperf.Runner()
for n in [100, 1000]:
xs = [mpz(i) for i in range(1, n + 1)]
runner.bench_func(f"sum({n})", mysum, xs)
17 changes: 17 additions & 0 deletions bench/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import os

if os.getenv("T") == "gmpy2.mpz":
from gmpy2 import mpz
elif os.getenv("T") == "flint.fmpz":
from flint import fmpz as mpz
elif os.getenv("T") == "int":
mpz = int
else:
from gmp import mpz # noqa: F401


def mysum(xs):
total = xs[0]
for t in xs[1:]:
total += t
return t
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ classifiers = ["Development Status :: 4 - Beta",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Free Threading :: 2 - Beta",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
Expand Down Expand Up @@ -62,8 +63,8 @@ select = ["E", "F", "I", "PT", "W", "Q", "SIM"]

[tool.cibuildwheel]
build-frontend = {name="build", args=["--verbose", "-Csetup-args=--vsenv"]}
enable = "pypy cpython-prerelease cpython-freethreading graalpy"
skip = "gp311_242* gp3*win*amd64*"
enable = "pypy cpython-prerelease graalpy"
skip = "gp3*win*amd64*"

before-all = "sh scripts/cibw_before_all.sh"
test-extras = "ci"
Expand Down
8 changes: 4 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def pytest_configure(config):
from hypothesis import settings

default = settings.get_profile("default")
settings.register_profile("default", settings(default, deadline=1600))
settings.register_profile("default", settings(default, deadline=3000))
ci = settings.get_profile("ci")
if platform.python_implementation() != "GraalVM":
ci = settings(ci, max_examples=10000)
Expand All @@ -20,9 +20,9 @@ def pytest_report_header(config):
print(f"""
Using the ZZ library v{gmp._zz_version}

Bits per digit : {gmp.mpz_info.bits_per_digit}
sizeof(zz_digit_t): {gmp.mpz_info.sizeof_digit}
Maximal bit count : {gmp.mpz_info.bitcnt_max}
Bits per digit : {gmp.mpz_info.bits_per_digit}
sizeof(digit) : {gmp.mpz_info.sizeof_digit}
Maximal bit count: {gmp.mpz_info.bitcnt_max}

The gmp module v{gmp.__version__}
""")
Expand Down
7 changes: 4 additions & 3 deletions tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def test_mpmath_normalize(sign, man, exp, prec, rnd):
sign = int(sign)
bc = mman.bit_length()
res = mpmath.libmp.libmpf._normalize(sign, man, exp, bc, prec, rnd)
assert all(type(_) is int for _ in res)
assert _mpmath_normalize(sign, mman, exp, bc, prec, rnd) == res


Expand All @@ -154,6 +155,7 @@ def test_mpmath_create(man, exp, prec, rnd):
mpmath = pytest.importorskip("mpmath")
mman = mpz(man)
res = mpmath.libmp.from_man_exp(man, exp, prec, rnd)
assert all(type(_) is int for _ in res)
assert _mpmath_create(mman, exp, prec, rnd) == res
assert mman == man
assert _mpmath_create(man, exp, prec, rnd) == res
Expand Down Expand Up @@ -233,9 +235,8 @@ def test_interfaces():
_mpmath_normalize(1, mpz(111), 11, 12, 13, 1j)


# See pypy/pypy#5368 and oracle/graalpython#593
@pytest.mark.skipif(platform.python_implementation() != "CPython",
reason="no way to specify a signature")
@pytest.mark.skipif(platform.python_implementation() == "GraalVM",
reason="oracle/graalpython#593")
def test_func_api():
for fn in ["comb", "factorial", "gcd", "isqrt", "lcm", "perm"]:
f = getattr(math, fn)
Expand Down
21 changes: 7 additions & 14 deletions tests/test_mpz.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ def test_format_interface():
mx.__format__(321)
with pytest.raises(ValueError, match="Unknown format code"):
format(mx, "q")
if platform.python_implementation() != "PyPy": # XXX: pypy/pypy#5311
with pytest.raises(ValueError, match="Unknown format code"):
format(mx, "\x81")
with pytest.raises(ValueError,
match="(Unknown format code|Invalid format specifier)"):
format(mx, "\x81")
with pytest.raises(ValueError,
match=(r"Negative zero coercion \(z\) not allowed|"
"Invalid conversion specification")):
Expand Down Expand Up @@ -195,10 +195,6 @@ def test_format_interface():
assert format(mx, ".,f") == "123.000,000"
assert format(mx, "._f") == "123.000_000"

if (platform.python_implementation() == "PyPy"
and sys.pypy_version_info[:3] <= (7, 3, 20)):
return # XXX: pypy/pypy#5311

try:
locale.setlocale(locale.LC_ALL, "ru_RU.UTF-8")
s = locale.localeconv()["thousands_sep"]
Expand Down Expand Up @@ -517,8 +513,6 @@ def test_divmod_bulk(x, y):
with pytest.raises(ZeroDivisionError):
x % my
return
if y < 0 and platform.python_implementation() == "GraalVM":
return # issue oracle/graalpython#534
r = x // y
assert mx // my == r
assert mx // y == r
Expand Down Expand Up @@ -700,11 +694,11 @@ def test_power_mod(x, y, z):
assert pow(mx, my, mz) == r
assert pow(mx, my, z) == r
assert pow(mx, y, mz) == r
if platform.python_implementation() == "PyPy":
return # XXX: pypy/pypy#5207
assert pow(x, my, mz) == r
assert pow(mx, y, z) == r
assert pow(x, my, z) == r
if platform.python_implementation() == "PyPy":
return # XXX: pypy/pypy#5207
assert pow(x, y, mz) == r


Expand Down Expand Up @@ -1075,9 +1069,8 @@ def f(n):
assert all(f.result() == 1 for f in futures)


# See pypy/pypy#5368 and oracle/graalpython#593
@pytest.mark.skipif(platform.python_implementation() != "CPython",
reason="no way to specify a signature")
@pytest.mark.skipif(platform.python_implementation() == "GraalVM",
reason="oracle/graalpython#593")
def test_int_api():
for meth in dir(int):
m = getattr(int, meth)
Expand Down
16 changes: 2 additions & 14 deletions utils.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
#ifndef UTILS_H
#define UTILS_H

#if defined(__MINGW32__) && defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Warray-bounds"
#endif
#if defined(__clang__)
# pragma GCC diagnostic push /* XXX: pypy/pypy#5312 */
# pragma GCC diagnostic ignored "-Wnewline-eof"
#endif
/* For GraalVM: unicodeobject.h, implicit conversion changes
signedness: 'enum PyUnicode_Kind' to 'int' */
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic push /* XXX: oracle/graalpython#580 */
# pragma GCC diagnostic ignored "-Wsign-conversion"
Expand All @@ -22,12 +16,6 @@
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
#endif
#if defined(__clang__)
# pragma GCC diagnostic pop
#endif
#if defined(__MINGW32__) && defined(__GNUC__)
# pragma GCC diagnostic pop
#endif

typedef struct gmp_pyargs {
Py_ssize_t maxpos;
Expand Down