From d38de36b8ba6b9a6caeae7c6ef4b3bab5e5b2d1d Mon Sep 17 00:00:00 2001 From: Pascal Bourgault Date: Thu, 25 Jul 2024 10:59:18 -0400 Subject: [PATCH] avoid inplace sort of input of lmom_ratios - add test --- CHANGELOG.rst | 4 ++++ lmoments3/__init__.py | 4 ++-- lmoments3/distr.py | 6 +++--- lmoments3/tests/test_lmoments.py | 5 ++++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cbb2861..c607107 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ Changelog ========= +version 1.0.7 (unreleased) +-------------------------- +- Avoid inplace modifications of input arrays in ``lmom_ratios``. + version 1.0.6 (2023-07-06) -------------------------- - Adopted `pyproject.toml` with `setuptools` backend for build configuration (PEP 517 and PEP 621) diff --git a/lmoments3/__init__.py b/lmoments3/__init__.py index 67aab44..7cc3004 100644 --- a/lmoments3/__init__.py +++ b/lmoments3/__init__.py @@ -86,7 +86,7 @@ def _samlmularge(x, nmom=5): try: x = np.asarray(x, dtype=np.float64) n = len(x) - x.sort() + x = np.sort(x) except ValueError: raise ValueError("Input data to estimate L-moments must be numeric.") @@ -142,7 +142,7 @@ def _samlmusmall(x, nmom=5): try: x = np.asarray(x, dtype=np.float64) n = len(x) - x.sort() + x = np.sort(x) except ValueError: raise ValueError("Input data to estimate L-moments must be numeric.") diff --git a/lmoments3/distr.py b/lmoments3/distr.py index 3a1d0c8..66ff77a 100644 --- a/lmoments3/distr.py +++ b/lmoments3/distr.py @@ -48,7 +48,7 @@ def _lmom_ratios(self, *shapes, locs, scale, nmom): """When overriding, *shapes can be replaced by the actual distribution's shape parameter(s), if any.""" raise NotImplementedError - def lmom_fit(self, data=[], lmom_ratios=[]): + def lmom_fit(self, data=None, lmom_ratios=None): """Fit the distribution function to the given data or given L-moments. :param data: Data to use in calculating the distribution parameters @@ -59,11 +59,11 @@ def lmom_fit(self, data=[], lmom_ratios=[]): :rtype: :class:`OrderedDict` """ n_min = self.numargs + 2 - if len(data) > 0: + if data is not None: if len(data) <= n_min: raise ValueError(f"At least {n_min} data points must be provided.") lmom_ratios = lm.lmom_ratios(data, nmom=n_min) - elif not lmom_ratios: + elif lmom_ratios is None: raise Exception("Either `data` or `lmom_ratios` must be provided.") elif len(lmom_ratios) < n_min: raise ValueError(f"At least {n_min} number of L-moments must be provided.") diff --git a/lmoments3/tests/test_lmoments.py b/lmoments3/tests/test_lmoments.py index 8813cf5..d224609 100644 --- a/lmoments3/tests/test_lmoments.py +++ b/lmoments3/tests/test_lmoments.py @@ -1,5 +1,6 @@ import unittest +import numpy as np from numpy.testing import assert_almost_equal import lmoments3 as lm @@ -9,10 +10,12 @@ class TestLmoments(unittest.TestCase): def test_samlmu(self): - testdata = [2.0, 3.0, 4.0, 2.4, 5.5, 1.2, 5.4, 2.2, 7.1, 1.3, 1.5] + testdata = np.array([2.0, 3.0, 4.0, 2.4, 5.5, 1.2, 5.4, 2.2, 7.1, 1.3, 1.5]) expected = [3.23636364, 1.14181818, 0.27388535, 0.02335456, -0.04246285] result = lm.lmom_ratios(testdata) assert_almost_equal(result, expected) + # Ensure input was not modified by `lmom_ratios`. + assert all(testdata[-3:] == [7.1, 1.3, 1.5]) def test_aic(self): data = [