architest / pymeeus

Library of astronomical algorithms in Python
GNU Lesser General Public License v3.0
59 stars 29 forks source link

0.5.11: pytest fails in 7 units #24

Open kloczek opened 7 months ago

kloczek commented 7 months ago

I'm packaging your module as an rpm package so I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

pytest 8.10.0 and python 3.9.

Here is pytest output: ```console + PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pymeeus-0.5.11-10.fc36.x86_64/usr/lib64/python3.9/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pymeeus-0.5.11-10.fc36.x86_64/usr/lib/python3.9/site-packages + /usr/bin/pytest -ra -m 'not network' ==================================================================================== test session starts ==================================================================================== platform linux -- Python 3.9.18, pytest-8.1.0, pluggy-1.4.0 rootdir: /home/tkloczko/rpmbuild/BUILD/pymeeus-0.5.11 configfile: pyproject.toml collected 251 items tests/test_angle.py ........................................ [ 15%] tests/test_coordinates.py ....................................... [ 31%] tests/test_curvefitting.py .FFFF [ 33%] tests/test_earth.py ................ [ 39%] tests/test_epoch.py ................................. [ 52%] tests/test_interpolation.py .FFF. [ 54%] tests/test_jupiter.py .......... [ 58%] tests/test_jupiterMoons.py ......... [ 62%] tests/test_mars.py .......... [ 66%] tests/test_mercury.py ............ [ 71%] tests/test_minor.py .. [ 72%] tests/test_moon.py .............. [ 77%] tests/test_neptune.py ...... [ 80%] tests/test_pluto.py .. [ 80%] tests/test_saturn.py .............. [ 86%] tests/test_sun.py ............ [ 91%] tests/test_uranus.py ........ [ 94%] tests/test_venus.py .............. [100%] ========================================================================================= FAILURES ========================================================================================== ____________________________________________________________________________ test_curvefitting_correlation_coeff ____________________________________________________________________________ def test_curvefitting_correlation_coeff(): """Tests the correlation_coeff() method of CurveFitting class""" > r = cf1.correlation_coeff() tests/test_curvefitting.py:92: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = CurveFitting([], []) def correlation_coeff(self): """This method returns the coefficient of correlation, as a float. :returns: Coefficient of correlation. :rtype: float >>> cf = CurveFitting([73.0, 38.0, 35.0, 42.0, 78.0, 68.0, 74.0, 42.0, ... 52.0, 54.0, 39.0, 61.0, 42.0, 49.0, 50.0, 62.0, ... 44.0, 39.0, 43.0, 54.0, 44.0, 37.0], ... [90.4, 125.3, 161.8, 143.4, 52.5, 50.8, 71.5, ... 152.8, 131.3, 98.5, 144.8, 78.1, 89.5, 63.9, ... 112.1, 82.0, 119.8, 161.2, 208.4, 111.6, 167.1, ... 162.1]) >>> r = cf.correlation_coeff() >>> print(round(r, 3)) -0.767 """ > n = self._N E AttributeError: 'CurveFitting' object has no attribute '_N' pymeeus/CurveFitting.py:321: AttributeError _____________________________________________________________________________ test_curvefitting_linear_fitting ______________________________________________________________________________ def test_curvefitting_linear_fitting(): """Tests the linear_fitting() method of CurveFitting class""" > a, b = cf1.linear_fitting() tests/test_curvefitting.py:100: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = CurveFitting([], []) def linear_fitting(self): """This method returns a tuple with the 'a', 'b' coefficients of the linear equation *'y = a*x + b'* that best fits the table data, using the least squares approach. :returns: 'a', 'b' coefficients of best linear equation fit. :rtype: tuple :raises: ZeroDivisionError if input data leads to a division by zero >>> cf = CurveFitting([73.0, 38.0, 35.0, 42.0, 78.0, 68.0, 74.0, 42.0, ... 52.0, 54.0, 39.0, 61.0, 42.0, 49.0, 50.0, 62.0, ... 44.0, 39.0, 43.0, 54.0, 44.0, 37.0], ... [90.4, 125.3, 161.8, 143.4, 52.5, 50.8, 71.5, ... 152.8, 131.3, 98.5, 144.8, 78.1, 89.5, 63.9, ... 112.1, 82.0, 119.8, 161.2, 208.4, 111.6, 167.1, ... 162.1]) >>> a, b = cf.linear_fitting() >>> print("a = {}\tb = {}".format(round(a, 2), round(b, 2))) a = -2.49 b = 244.18 """ > n = self._N E AttributeError: 'CurveFitting' object has no attribute '_N' pymeeus/CurveFitting.py:351: AttributeError ____________________________________________________________________________ test_curvefitting_quadratic_fitting ____________________________________________________________________________ def test_curvefitting_quadratic_fitting(): """Tests the quadratic_fitting() method of CurveFitting class""" > a, b, c = cf3.quadratic_fitting() tests/test_curvefitting.py:118: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = CurveFitting([], []) def quadratic_fitting(self): """This method returns a tuple with the 'a', 'b', 'c' coefficients of the quadratic equation *'y = a*x*x + b*x + c'* that best fits the table data, using the least squares approach. :returns: 'a', 'b', 'c' coefficients of best quadratic equation fit. :rtype: tuple :raises: ZeroDivisionError if input data leads to a division by zero >>> cf2 = CurveFitting([-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, ... 2.0, 2.5,3.0], ... [-9.372, -3.821, 0.291, 3.730, 5.822, 8.324, ... 9.083, 6.957, 7.006, 0.365, -1.722]) >>> a, b, c = cf2.quadratic_fitting() >>> print("a = {}; b = {}; c = {}".format(round(a, 2), round(b, 2), ... round(c, 2))) a = -2.22; b = 3.76; c = 6.64 """ > n = self._N E AttributeError: 'CurveFitting' object has no attribute '_N' pymeeus/CurveFitting.py:384: AttributeError _____________________________________________________________________________ test_curvefitting_general_fitting _____________________________________________________________________________ def test_curvefitting_general_fitting(): """Tests the general_fitting() method of CurveFitting class""" # Let's define the three functions to be used for fitting def sin1(x): return sin(radians(x)) def sin2(x): return sin(radians(2.0*x)) def sin3(x): return sin(radians(3.0*x)) > a, b, c = cf4.general_fitting(sin1, sin2, sin3) tests/test_curvefitting.py:142: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = CurveFitting([], []), f0 = .sin1 at 0x7f8356bea1f0> f1 = .sin2 at 0x7f8356bea280>, f2 = .sin3 at 0x7f8356bea310> def general_fitting(self, f0, f1=lambda *args: 0.0, f2=lambda *args: 0.0): """This method returns a tuple with the 'a', 'b', 'c' coefficients of the general equation *'y = a*f0(x) + b*f1(x) + c*f2(x)'* that best fits the table data, using the least squares approach. :param f0, f1, f2: Functions used to build the general equation. :type f0, f1, f2: function :returns: 'a', 'b', 'c' coefficients of best general equation fit. :rtype: tuple :raises: ZeroDivisionError if input functions are null or input data leads to a division by zero >>> cf4 = CurveFitting([3, 20, 34, 50, 75, 88, 111, 129, 143, 160, 183, ... 200, 218, 230, 248, 269, 290, 303, 320, 344], ... [0.0433, 0.2532, 0.3386, 0.3560, 0.4983, 0.7577, ... 1.4585, 1.8628, 1.8264, 1.2431, -0.2043, ... -1.2431, -1.8422, -1.8726, -1.4889, -0.8372, ... -0.4377, -0.3640, -0.3508, -0.2126]) >>> def sin1(x): return sin(radians(x)) >>> def sin2(x): return sin(radians(2.0*x)) >>> def sin3(x): return sin(radians(3.0*x)) >>> a, b, c = cf4.general_fitting(sin1, sin2, sin3) >>> print("a = {}; b = {}; c = {}".format(round(a, 2), round(b, 2), ... round(c, 2))) a = 1.2; b = -0.77; c = 0.39 >>> cf5 = CurveFitting([0, 1.2, 1.4, 1.7, 2.1, 2.2]) >>> a, b, c = cf5.general_fitting(sqrt) >>> print("a = {}; b = {}; c = {}".format(round(a, 3), round(b, 3), ... round(c, 3))) a = 1.016; b = 0.0; c = 0.0 """ m = 0 p = 0 q = 0 r = 0 s = 0 t = 0 u = 0 v = 0 w = 0 xl = list(self._x) yl = list(self._y) for i, value in enumerate(xl): x = value y = yl[i] m += f0(x) * f0(x) p += f0(x) * f1(x) q += f0(x) * f2(x) r += f1(x) * f1(x) s += f1(x) * f2(x) t += f2(x) * f2(x) u += y * f0(x) v += y * f1(x) w += y * f2(x) if abs(r) < TOL and abs(t) < TOL and abs(m) >= TOL: return (u / m, 0.0, 0.0) if abs(m * r * t) < TOL: > raise ZeroDivisionError("Invalid input functions: They are null") E ZeroDivisionError: Invalid input functions: They are null pymeeus/CurveFitting.py:467: ZeroDivisionError __________________________________________________________________________________ test_interpolation_call __________________________________________________________________________________ def test_interpolation_call(): """Tests the __call__() method of Interpolation class""" m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) assert abs(m(-0.8) - (-0.52)) < TOL, \ "ERROR: In 1st __call__() test, output value doesn't match" assert abs(m(0.7) - 2.93) < TOL, \ "ERROR: In 2nd __call__() test, output value doesn't match" assert abs(m(-1.0) - (-2.0)) < TOL, \ "ERROR: In 3rd __call__() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75]) assert abs(m(-2.0) - 5.0) < TOL, \ "ERROR: In 4th __call__() test, output value doesn't match" assert abs(m(2.5) - (-1.75)) < TOL, \ "ERROR: In 5th __call__() test, output value doesn't match" # This interpolation test uses Right Ascension > a = Angle(i_ra(11.0)) tests/test_interpolation.py:118: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Interpolation([], []), x = 11.0 def __call__(self, x): """Method to interpolate the function at a given 'x'. :param x: Point where the interpolation will be carried out. :type x: int, float, :py:class:`Angle` :returns: Resulting value of the interpolation. :rtype: float :raises: ValueError if input value is outside of interpolation range. :raises: TypeError if input value is of wrong type. >>> i = Interpolation([7, 8, 9], [0.884226, 0.877366, 0.870531]) >>> y = round(i(8.18125), 6) >>> print(y) 0.876125 """ # Check if input value is of correct type if isinstance(x, (int, float, Angle)): # Check if 'x' already belongs to the data table for i in range(len(self._x)): if abs(x - self._x[i]) < self._tol: return self._y[i] # We don't need to look further # Check if Newton coefficients table is not empty if len(self._table) == 0: > raise RuntimeError("Internal table is empty. Use set().") E RuntimeError: Internal table is empty. Use set(). pymeeus/Interpolation.py:404: RuntimeError _______________________________________________________________________________ test_interpolation_derivative _______________________________________________________________________________ def test_interpolation_derivative(): """Tests the derivative() method of Interpolation class""" m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) assert abs(m.derivative(-1.0) - 8.0) < TOL, \ "ERROR: In 1st derivative() test, output value doesn't match" assert abs(m.derivative(0.0) - 2.0) < TOL, \ "ERROR: In 2nd derivative() test, output value doesn't match" assert abs(m.derivative(0.5) - (-1.0)) < TOL, \ "ERROR: In 3rd derivative() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75]) assert abs(m.derivative(-3.0) - (-8.0)) < TOL, \ "ERROR: In 4th derivative() test, output value doesn't match" assert abs(m.derivative(0.0) - (-2.0)) < TOL, \ "ERROR: In 5th derivative() test, output value doesn't match" assert abs(m.derivative(2.5) - 3.0) < TOL, \ "ERROR: In 6th derivative() test, output value doesn't match" # Do test with an interpolation object with 6 table entries, based on sine # We need to adjust the result because degrees were used instead of radians > res = degrees(i_sine.derivative(30.0)) tests/test_interpolation.py:158: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Interpolation([], []), x = 30.0 def derivative(self, x): """Method to compute the derivative from interpolation polynomial. :param x: Point where the interpolation derivative will be carried out. :type x: int, float, :py:class:`Angle` :returns: Resulting value of the interpolation derivative. :rtype: float :raises: ValueError if input value is outside of interpolation range. :raises: TypeError if input value is of wrong type. >>> m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) >>> m.derivative(-1.0) 8.0 >>> m.derivative(0.5) -1.0 """ # Check if input value is of correct type if isinstance(x, (int, float, Angle)): # Check that x is within interpolation table values > if x < self._x[0] or x > self._x[-1]: E IndexError: list index out of range pymeeus/Interpolation.py:438: IndexError __________________________________________________________________________________ test_interpolation_root __________________________________________________________________________________ def test_interpolation_root(): """Tests the root() method of Interpolation class""" m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) assert abs(m.root() - (-0.7207592200561265)) < TOL, \ "ERROR: In 1st root() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75]) assert abs(m.root(-2.0, 0.0) - (-1.0)) < TOL, \ "ERROR: In 2nd root() test, output value doesn't match" assert abs(m.root() - (-1.0)) < TOL, \ "ERROR: In 3rd root() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5, 3.5], [12.0, -3.0, -1.75, 2.25]) assert abs(m.root(0.0, 3.15) - 3.0) < TOL, \ "ERROR: In 4th root() test, output value doesn't match" # Let's do some tests with Angles > assert abs(i_angles1.root() - 26.798732705) < TOL, \ "ERROR: In 5th root() test, output value doesn't match" tests/test_interpolation.py:185: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Interpolation([], []), xl = 0, xh = 0, max_iter = 1000 def root(self, xl=0, xh=0, max_iter=1000): """Method to find the root inside the [xl, xh] range. This method applies, in principle, the Newton method to find the root; however, if conditions are such that Newton method may not bei properly behaving or converging, then it switches to the linear Interpolation method. If values xl, xh are not given, the limits of the interpolation table values will be used. .. note:: This method returns a ValueError exception if the corresponding yl = f(xl) and yh = f(xh) values have the same sign. In that case, the method assumes there is no root in the [xl, xh] interval. .. note:: If any of the xl, xh values is beyond the limits given by the interpolation values, its value will be set to the corresponding limit. .. note:: If xl == xh (and not zero), a ValueError exception is raised. .. note:: If the method doesn't converge within max_iter ierations, then a ValueError exception is raised. :param xl: Lower limit of interval where the root will be looked for. :type xl: int, float, :py:class:`Angle` :param xh: Higher limit of interval where the root will be looked for. :type xh: int, float, :py:class:`Angle` :param max_iter: Maximum number of iterations allowed. :type max_iter: int :returns: Root of the interpolated function within [xl, xh] interval. :rtype: int, float, :py:class:`Angle` :raises: ValueError if yl = f(xl), yh = f(xh) have same sign. :raises: ValueError if xl == xh. :raises: ValueError if maximum number of iterations is exceeded. :raises: TypeError if input value is of wrong type. >>> m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) >>> round(m.root(), 8) -0.72075922 """ # Get the limits of the interpolation table > xmin = self._x[0] E IndexError: list index out of range pymeeus/Interpolation.py:503: IndexError ================================================================================== short test summary info ================================================================================== FAILED tests/test_curvefitting.py::test_curvefitting_correlation_coeff - AttributeError: 'CurveFitting' object has no attribute '_N' FAILED tests/test_curvefitting.py::test_curvefitting_linear_fitting - AttributeError: 'CurveFitting' object has no attribute '_N' FAILED tests/test_curvefitting.py::test_curvefitting_quadratic_fitting - AttributeError: 'CurveFitting' object has no attribute '_N' FAILED tests/test_curvefitting.py::test_curvefitting_general_fitting - ZeroDivisionError: Invalid input functions: They are null FAILED tests/test_interpolation.py::test_interpolation_call - RuntimeError: Internal table is empty. Use set(). FAILED tests/test_interpolation.py::test_interpolation_derivative - IndexError: list index out of range FAILED tests/test_interpolation.py::test_interpolation_root - IndexError: list index out of range =============================================================================== 7 failed, 244 passed in 1.93s =============================================================================== ```

Above is againft curent master.

Please let me know if you need more details or want me to perform some diagnostics.

architest commented 7 months ago

Dear Tomasz

Thank you for your detailed report. It is strange because last time I checked all tests were OK, but I'll take a look at it.

Regards,

Dago

On Sat, Mar 9, 2024 at 11:16 PM Tomasz Kłoczko @.***> wrote:

I'm packaging your module as an rpm package so I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

  • python3 -sBm build -w --no-isolation
  • because I'm calling build with --no-isolation I'm using during all processes only locally installed modules
  • install .whl file in </install/prefix> using installer module
  • run pytest with $PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>
  • build is performed in env which is cut off from access to the public network (pytest is executed with -m "not network")

pytest 8.10.0 and python 3.9. Here is pytest output:

  • PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pymeeus-0.5.11-10.fc36.x86_64/usr/lib64/python3.9/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pymeeus-0.5.11-10.fc36.x86_64/usr/lib/python3.9/site-packages+ /usr/bin/pytest -ra -m 'not network'==================================================================================== test session starts ====================================================================================platform linux -- Python 3.9.18, pytest-8.1.0, pluggy-1.4.0rootdir: /home/tkloczko/rpmbuild/BUILD/pymeeus-0.5.11configfile: pyproject.tomlcollected 251 items tests/test_angle.py ........................................ [ 15%]tests/test_coordinates.py ....................................... [ 31%]tests/test_curvefitting.py .FFFF [ 33%]tests/test_earth.py ................ [ 39%]tests/test_epoch.py ................................. [ 52%]tests/test_interpolation.py .FFF. [ 54%]tests/test_jupiter.py .......... [ 58%]tests/test_jupiterMoons.py ......... [ 62%]tests/test_mars.py .......... [ 66%]tests/test_mercury.py ............ [ 71%]tests/test_minor.py .. [ 72%]tests/test_moon.py .............. [ 77%]tests/test_neptune.py ...... [ 80%]tests/test_pluto.py .. [ 80%]tests/test_saturn.py .............. [ 86%]tests/test_sun.py ............ [ 91%]tests/test_uranus.py ........ [ 94%]tests/test_venus.py .............. [100%] ========================================================================================= FAILURES ==========================================================================================____ test_curvefitting_correlation_coeff ____ def test_curvefitting_correlation_coeff(): """Tests the correlation_coeff() method of CurveFitting class"""
  r = cf1.correlation_coeff()

tests/testcurvefitting.py:92: self = CurveFitting([], []) def correlation_coeff(self): """This method returns the coefficient of correlation, as a float. :returns: Coefficient of correlation. :rtype: float

cf = CurveFitting([73.0, 38.0, 35.0, 42.0, 78.0, 68.0, 74.0, 42.0, ... 52.0, 54.0, 39.0, 61.0, 42.0, 49.0, 50.0, 62.0, ... 44.0, 39.0, 43.0, 54.0, 44.0, 37.0], ... [90.4, 125.3, 161.8, 143.4, 52.5, 50.8, 71.5, ... 152.8, 131.3, 98.5, 144.8, 78.1, 89.5, 63.9, ... 112.1, 82.0, 119.8, 161.2, 208.4, 111.6, 167.1, ... 162.1]) >>> r = cf.correlation_coeff() >>> print(round(r, 3)) -0.767 """

  n = self._NE       AttributeError: 'CurveFitting' object has no attribute '_N'

pymeeus/CurveFitting.py:321: AttributeError_ test_curvefitting_linear_fitting __ def test_curvefitting_linear_fitting(): """Tests the linear_fitting() method of CurveFitting class"""

  a, b = cf1.linear_fitting()

tests/testcurvefitting.py:100: self = CurveFitting([], []) def linear_fitting(self): """This method returns a tuple with the 'a', 'b' coefficients of the linear equation 'y = ax + b'* that best fits the table data, using the least squares approach. :returns: 'a', 'b' coefficients of best linear equation fit. :rtype: tuple :raises: ZeroDivisionError if input data leads to a division by zero

cf = CurveFitting([73.0, 38.0, 35.0, 42.0, 78.0, 68.0, 74.0, 42.0, ... 52.0, 54.0, 39.0, 61.0, 42.0, 49.0, 50.0, 62.0, ... 44.0, 39.0, 43.0, 54.0, 44.0, 37.0], ... [90.4, 125.3, 161.8, 143.4, 52.5, 50.8, 71.5, ... 152.8, 131.3, 98.5, 144.8, 78.1, 89.5, 63.9, ... 112.1, 82.0, 119.8, 161.2, 208.4, 111.6, 167.1, ... 162.1]) >>> a, b = cf.linear_fitting() >>> print("a = {}\tb = {}".format(round(a, 2), round(b, 2))) a = -2.49 b = 244.18 """

  n = self._NE       AttributeError: 'CurveFitting' object has no attribute '_N'

pymeeus/CurveFitting.py:351: AttributeError____ test_curvefitting_quadratic_fitting ____ def test_curvefitting_quadratic_fitting(): """Tests the quadratic_fitting() method of CurveFitting class"""

  a, b, c = cf3.quadratic_fitting()

tests/testcurvefitting.py:118: self = CurveFitting([], []) def quadratic_fitting(self): """This method returns a tuple with the 'a', 'b', 'c' coefficients of the quadratic equation 'y = axx + bx + c'* that best fits the table data, using the least squares approach. :returns: 'a', 'b', 'c' coefficients of best quadratic equation fit. :rtype: tuple :raises: ZeroDivisionError if input data leads to a division by zero

cf2 = CurveFitting([-2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, ... 2.0, 2.5,3.0], ... [-9.372, -3.821, 0.291, 3.730, 5.822, 8.324, ... 9.083, 6.957, 7.006, 0.365, -1.722]) >>> a, b, c = cf2.quadratic_fitting() >>> print("a = {}; b = {}; c = {}".format(round(a, 2), round(b, 2), ... round(c, 2))) a = -2.22; b = 3.76; c = 6.64 """

  n = self._NE       AttributeError: 'CurveFitting' object has no attribute '_N'

pymeeus/CurveFitting.py:384: AttributeError_____ test_curvefitting_generalfitting ____ def test_curvefitting_general_fitting(): """Tests the general_fitting() method of CurveFitting class"""

Let's define the three functions to be used for fitting def sin1(x): return sin(radians(x))

def sin2(x): return sin(radians(2.0x)) def sin3(x): return sin(radians(3.0x))

  a, b, c = cf4.general_fitting(sin1, sin2, sin3)

tests/testcurvefitting.py:142: self = CurveFitting([], []), f0 = <function test_curvefitting_general_fitting..sin1 at 0x7f8356bea1f0>f1 = <function test_curvefitting_general_fitting..sin2 at 0x7f8356bea280>, f2 = <function test_curvefitting_general_fitting..sin3 at 0x7f8356bea310> def general_fitting(self, f0, f1=lambda args: 0.0, f2=lambda args: 0.0): """This method returns a tuple with the 'a', 'b', 'c' coefficients of the general equation 'y = af0(x) + bf1(x) + cf2(x)'* that best fits the table data, using the least squares approach. :param f0, f1, f2: Functions used to build the general equation. :type f0, f1, f2: function :returns: 'a', 'b', 'c' coefficients of best general equation fit. :rtype: tuple :raises: ZeroDivisionError if input functions are null or input data leads to a division by zero

cf4 = CurveFitting([3, 20, 34, 50, 75, 88, 111, 129, 143, 160, 183, ... 200, 218, 230, 248, 269, 290, 303, 320, 344], ... [0.0433, 0.2532, 0.3386, 0.3560, 0.4983, 0.7577, ... 1.4585, 1.8628, 1.8264, 1.2431, -0.2043, ... -1.2431, -1.8422, -1.8726, -1.4889, -0.8372, ... -0.4377, -0.3640, -0.3508, -0.2126]) >>> def sin1(x): return sin(radians(x)) >>> def sin2(x): return sin(radians(2.0x)) >>> def sin3(x): return sin(radians(3.0x)) >>> a, b, c = cf4.general_fitting(sin1, sin2, sin3) >>> print("a = {}; b = {}; c = {}".format(round(a, 2), round(b, 2), ... round(c, 2))) a = 1.2; b = -0.77; c = 0.39 cf5 = CurveFitting([0, 1.2, 1.4, 1.7, 2.1, 2.2]) >>> a, b, c = cf5.general_fitting(sqrt) >>> print("a = {}; b = {}; c = {}".format(round(a, 3), round(b, 3), ... round(c, 3))) a = 1.016; b = 0.0; c = 0.0 """ m = 0 p = 0 q = 0 r = 0 s = 0 t = 0 u = 0 v = 0 w = 0 xl = list(self._x) yl = list(self._y) for i, value in enumerate(xl): x = value y = yl[i] m += f0(x) f0(x) p += f0(x) f1(x) q += f0(x) f2(x) r += f1(x) f1(x) s += f1(x) f2(x) t += f2(x) f2(x) u += y f0(x) v += y f1(x) w += y f2(x) if abs(r) < TOL and abs(t) < TOL and abs(m) >= TOL: return (u / m, 0.0, 0.0) if abs(m r * t) < TOL: raise ZeroDivisionError("Invalid input functions: They are null")E ZeroDivisionError: Invalid input functions: They are null pymeeus/CurveFitting.py:467: ZeroDivisionError__ test_interpolation_call __ def test_interpolation_call(): """Tests the call() method of Interpolation class""" m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) assert abs(m(-0.8) - (-0.52)) < TOL, \ "ERROR: In 1st call() test, output value doesn't match" assert abs(m(0.7) - 2.93) < TOL, \ "ERROR: In 2nd call() test, output value doesn't match" assert abs(m(-1.0) - (-2.0)) < TOL, \ "ERROR: In 3rd call() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75]) assert abs(m(-2.0) - 5.0) < TOL, \ "ERROR: In 4th call() test, output value doesn't match" assert abs(m(2.5) - (-1.75)) < TOL, \ "ERROR: In 5th call() test, output value doesn't match"

This interpolation test uses Right Ascension

a = Angle(i_ra(11.0)) tests/testinterpolation.py:118: self = Interpolation([], []), x = 11.0 def call(self, x): """Method to interpolate the function at a given 'x'. :param x: Point where the interpolation will be carried out. :type x: int, float, :py:class:Angle :returns: Resulting value of the interpolation. :rtype: float :raises: ValueError if input value is outside of interpolation range. :raises: TypeError if input value is of wrong type. i = Interpolation([7, 8, 9], [0.884226, 0.877366, 0.870531]) >>> y = round(i(8.18125), 6) >>> print(y) 0.876125 """

Check if input value is of correct type if isinstance(x, (int, float, Angle)): # Check if 'x' already belongs to the data table for i in range(len(self._x)): if abs(x - self._x[i]) < self._tol: return self._y[i] # We don't need to look further # Check if Newton coefficients table is not empty if len(self._table) == 0:

raise RuntimeError("Internal table is empty. Use set().")E RuntimeError: Internal table is empty. Use set(). pymeeus/Interpolation.py:404: RuntimeError_ test_interpolationderivative def test_interpolation_derivative(): """Tests the derivative() method of Interpolation class""" m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) assert abs(m.derivative(-1.0) - 8.0) < TOL, \ "ERROR: In 1st derivative() test, output value doesn't match" assert abs(m.derivative(0.0) - 2.0) < TOL, \ "ERROR: In 2nd derivative() test, output value doesn't match" assert abs(m.derivative(0.5) - (-1.0)) < TOL, \ "ERROR: In 3rd derivative() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75]) assert abs(m.derivative(-3.0) - (-8.0)) < TOL, \ "ERROR: In 4th derivative() test, output value doesn't match" assert abs(m.derivative(0.0) - (-2.0)) < TOL, \ "ERROR: In 5th derivative() test, output value doesn't match" assert abs(m.derivative(2.5) - 3.0) < TOL, \ "ERROR: In 6th derivative() test, output value doesn't match"

Do test with an interpolation object with 6 table entries, based on sine # We need to adjust the result because degrees were used instead of radians

res = degrees(i_sine.derivative(30.0)) tests/testinterpolation.py:158: self = Interpolation([], []), x = 30.0 def derivative(self, x): """Method to compute the derivative from interpolation polynomial. :param x: Point where the interpolation derivative will be carried out. :type x: int, float, :py:class:Angle :returns: Resulting value of the interpolation derivative. :rtype: float :raises: ValueError if input value is outside of interpolation range. :raises: TypeError if input value is of wrong type. m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) >>> m.derivative(-1.0) 8.0 >>> m.derivative(0.5) -1.0 """

Check if input value is of correct type if isinstance(x, (int, float, Angle)): # Check that x is within interpolation table values

if x < self._x[0] or x > self._x[-1]:E IndexError: list index out of range pymeeus/Interpolation.py:438: IndexError__ test_interpolation_root __ def test_interpolation_root(): """Tests the root() method of Interpolation class""" m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) assert abs(m.root() - (-0.7207592200561265)) < TOL, \ "ERROR: In 1st root() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5], [12.0, -3.0, -1.75]) assert abs(m.root(-2.0, 0.0) - (-1.0)) < TOL, \ "ERROR: In 2nd root() test, output value doesn't match" assert abs(m.root() - (-1.0)) < TOL, \ "ERROR: In 3rd root() test, output value doesn't match" m = Interpolation([-3.0, 0.0, 2.5, 3.5], [12.0, -3.0, -1.75, 2.25]) assert abs(m.root(0.0, 3.15) - 3.0) < TOL, \ "ERROR: In 4th root() test, output value doesn't match"

Let's do some tests with Angles

assert abs(i_angles1.root() - 26.798732705) < TOL, \ "ERROR: In 5th root() test, output value doesn't match" tests/testinterpolation.py:185: self = Interpolation([], []), xl = 0, xh = 0, max_iter = 1000 def root(self, xl=0, xh=0, max_iter=1000): """Method to find the root inside the [xl, xh] range. This method applies, in principle, the Newton method to find the root; however, if conditions are such that Newton method may not bei properly behaving or converging, then it switches to the linear Interpolation method. If values xl, xh are not given, the limits of the interpolation table values will be used. .. note:: This method returns a ValueError exception if the corresponding yl = f(xl) and yh = f(xh) values have the same sign. In that case, the method assumes there is no root in the [xl, xh] interval. .. note:: If any of the xl, xh values is beyond the limits given by the interpolation values, its value will be set to the corresponding limit. .. note:: If xl == xh (and not zero), a ValueError exception is raised. .. note:: If the method doesn't converge within max_iter ierations, then a ValueError exception is raised. :param xl: Lower limit of interval where the root will be looked for. :type xl: int, float, :py:class:Angle :param xh: Higher limit of interval where the root will be looked for. :type xh: int, float, :py:class:Angle :param max_iter: Maximum number of iterations allowed. :type max_iter: int :returns: Root of the interpolated function within [xl, xh] interval. :rtype: int, float, :py:class:Angle :raises: ValueError if yl = f(xl), yh = f(xh) have same sign. :raises: ValueError if xl == xh. :raises: ValueError if maximum number of iterations is exceeded. :raises: TypeError if input value is of wrong type. m = Interpolation([-1.0, 0.0, 1.0], [-2.0, 3.0, 2.0]) >>> round(m.root(), 8) -0.72075922 """

Get the limits of the interpolation table

xmin = self._x[0]E IndexError: list index out of range pymeeus/Interpolation.py:503: IndexError================================================================================== short test summary info ==================================================================================FAILED tests/test_curvefitting.py::test_curvefitting_correlation_coeff - AttributeError: 'CurveFitting' object has no attribute '_N'FAILED tests/test_curvefitting.py::test_curvefitting_linear_fitting - AttributeError: 'CurveFitting' object has no attribute '_N'FAILED tests/test_curvefitting.py::test_curvefitting_quadratic_fitting - AttributeError: 'CurveFitting' object has no attribute '_N'FAILED tests/test_curvefitting.py::test_curvefitting_general_fitting - ZeroDivisionError: Invalid input functions: They are nullFAILED tests/test_interpolation.py::test_interpolation_call - RuntimeError: Internal table is empty. Use set().FAILED tests/test_interpolation.py::test_interpolation_derivative - IndexError: list index out of rangeFAILED tests/test_interpolation.py::test_interpolation_root - IndexError: list index out of range=============================================================================== 7 failed, 244 passed in 1.93s ===============================================================================

Above is againft curent master.

Please let me know if you need more details or want me to perform some diagnostics.

— Reply to this email directly, view it on GitHub https://github.com/architest/pymeeus/issues/24, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFQIZWKSD4V6XZ2QZEKFIY3YXOC2TAVCNFSM6AAAAABEONQTFCVHI2DSMVQWIX3LMV43ASLTON2WKOZSGE3TONBSGM2TINI . You are receiving this because you are subscribed to this thread.Message ID: @.***>

anarcat commented 7 months ago

we have similar failures in debian, even with the latest release (0.5.12). here's a build log against Debian unstable, which I believe is against Python 3.12:

pymeeus_0.5.12+dfsg1-1_amd64.build.txt

tests pass fine in Debian bookworm (python 3.11), which is really odd considering the reporter here says they fail in 3.9. so i'm not sure what's going on ... could this be flaky?

this was reported in Debian as https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1067290 and is a release critical bug, which means that it's keeping pymeeus from shipping in Debian (and a whole slew of dependencies as well, of course). :)

i hope that helps!

anarcat commented 7 months ago

pytest 8.10.0 and python 3.9.

one thing I just noticed is that we're also testing with pytest 8 here in Debian unstable, while bookworm has the older 7.2. pytest 8 was a pretty big release, with lots of breaking changes:

https://docs.pytest.org/en/8.0.x/changelog.html#pytest-8-0-0rc1-2023-12-30

i can indeed confirm that upgrading pytest, even just on debian bookworm, suffices to reproduce this issue.

the pattern here is that _N is not set (and _x is either empty or not the expected size), which probably means that either _compute_parameters is not being called or set() is not being called. now this whole thing is like a weird magic box to me, but it seems to me that a change in the pytest runners could have changed the order of how the tests are called, which, in turn, would break such initialization routines.

@architest did you try testing with pytest 8?

update: HA! found it! it's 7.2 which deprecated plain setup()! PR coming up