From a3d29d2dab77f7d99d4563f643a403e5be121656 Mon Sep 17 00:00:00 2001 From: Bjorn Date: Fri, 26 Apr 2024 14:54:34 +0200 Subject: [PATCH] Add test to guard for refcounting error (#42) * Add test to guard for refcounting error * tweak test levels * fix sign * update AnyODE * update anyode, avoid increase in None refcount --- .woodpecker.yaml | 2 +- external/anyode | 2 +- pyodeint/__init__.py | 4 ++-- pyodeint/tests/test_odeint_numpy.py | 26 ++++++++++++++++++++++---- scripts/ci.sh | 2 +- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.woodpecker.yaml b/.woodpecker.yaml index e92a19b..99d43a9 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -9,7 +9,7 @@ when: steps: - name: build-and-test - image: cont-reg.bjodah.se:443/bjodah/triceratops-3:14 #bjodahimg20dev:v1.1.0 + image: cont-reg.bjodah.se:443/bjodah/triceratops-3:16 #bjodahimg20dev:v1.1.0 environment: - PYTHONMALLOC=malloc commands: diff --git a/external/anyode b/external/anyode index 6ca8f77..ac350a9 160000 --- a/external/anyode +++ b/external/anyode @@ -1 +1 @@ -Subproject commit 6ca8f7716abdab9b069dd0d47a826a47845b559e +Subproject commit ac350a937b0fe74a4da4f9b6f983c982b1cce0d2 diff --git a/pyodeint/__init__.py b/pyodeint/__init__.py index 25bdb68..f139a2d 100644 --- a/pyodeint/__init__.py +++ b/pyodeint/__init__.py @@ -22,9 +22,9 @@ def get_include(): def _bs(kwargs): - # DEPRECATED accept 'bs' as short for 'bulirsh_stoer' + # DEPRECATED accept 'bs' as short for 'bulirsch_stoer' if kwargs.get('method', '-') == 'bs': - warnings.warn('Using method="bs" is depreacted, use "bulirsh_stoer" instead.', DeprecationWarning) + warnings.warn('Using method="bs" is depreacted, use "bulirsch_stoer" instead.', DeprecationWarning) kwargs['method'] = 'bulirsch_stoer' return kwargs diff --git a/pyodeint/tests/test_odeint_numpy.py b/pyodeint/tests/test_odeint_numpy.py index c0754d9..74588ea 100644 --- a/pyodeint/tests/test_odeint_numpy.py +++ b/pyodeint/tests/test_odeint_numpy.py @@ -1,10 +1,20 @@ # -*- coding: utf-8 -*- +import gc import os +import sys import numpy as np import pytest from pyodeint import integrate_adaptive, integrate_predefined +def _get_refcount_None(): + if hasattr(sys, 'getrefcount'): + gc.collect() + gc.collect() + return sys.getrefcount(None) + else: # e.g. pypy + return 0 + decay_analytic = { 0: lambda y0, k, t: ( @@ -53,7 +63,7 @@ def j(t, y, jmat_out, dfdx_out): methods = [ ('dopri5', False), - ('bs', False), + ('bulirsch_stoer', False), # rosenbrock4 suffered a massive performance regression: # - https://github.com/headmyshoulder/odeint-v2/issues/189 # - https://github.com/bjodah/pyodeint/pull/16 @@ -70,9 +80,17 @@ def test_integrate_adaptive(method, use_jac): if not use_jac: j = None kwargs = dict(x0=0, xend=3, dx0=1e-10, atol=1e-8, rtol=1e-8, method=method) - # Run twice to catch possible side-effects: - xout, yout, info = integrate_adaptive(f, j, y0, **kwargs) - xout, yout, info = integrate_adaptive(f, j, y0, **kwargs) + # Run multiple times to catch possible side-effects: + nIter = 100 + for ii in range(nIter): + if ii == 1: + nNone1 = _get_refcount_None() + xout, yout, info = integrate_adaptive(f, j, y0, **kwargs) + gc.collect() + nNone2 = _get_refcount_None() + delta = nNone2 - nNone1 + assert -nIter//10 < delta < nIter//10 + assert info['success'] assert info['atol'] == 1e-8 and info['rtol'] == 1e-8 assert info['nfev'] > 0 diff --git a/scripts/ci.sh b/scripts/ci.sh index 87c7aa0..2405f15 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -12,7 +12,7 @@ source /opt-3/cpython-v3.11-apt-deb/bin/activate python3 setup.py sdist CC=gcc CXX=g++ python3 -m pip install --ignore-installed dist/*.tar.gz -(cd /; python3 -m pytest --pyargs $PKG_NAME) +(cd /; python3 -m pytest --pyargs $PKG_NAME -v) CC=gcc CXX=g++ python3 -m pip install -e .[all] python3 -m pip install pytest-cov pytest-flakes matplotlib sphinx numpydoc sphinx_rtd_theme PYTHONPATH=$(pwd) PYTHON=python3 ./scripts/run_tests.sh --cov $PKG_NAME --cov-report html