Skip to content

Runtime error from Angle.to_string() on older python/numpy combinations #18989

Open

Description

@mhvk

Description

While testing for #18986, I found that tests on angles failed with a strange RuntimeError:

In [1]: from astropy.coordinates import Angle
WARNING: AstropyDeprecationWarning: The TestRunner class is deprecated and may be removed in a future version.
        Use pytest instead. [astropy.tests.runner]
WARNING: AstropyDeprecationWarning: The TestRunnerBase class is deprecated and may be removed in a future version.
        Use pytest instead. [astropy.utils.decorators]

In [2]: str(Angle("54.12412", unit="deg"))
/home/mhvk/data/mhvk/packages/astropy/.tox/py311-test-oldestdeps-alldeps/lib/python3.11/site-packages/numpy/lib/_function_base_impl.py:2605: RuntimeWarning: invalid value encountered in do_format (vectorized)
  outputs = ufunc(*inputs)
Out[2]: np.str_('54d07m26.832s')

I tried to determine what combinations were problematic, and it seemed to be at least python 3.11 or 3.12 and numpy 2.0 or 2.1 (2.2 is not available for python 3.11, did not test for python 3.12).

It boils down to the use of np.vectorize in Angle.to_string(), and a replacement with np.nditer solves it. Still, it is very weird, including that it was not seen before (it is not present with python 3.13/numpy 2.3).

Expected behavior

No response

How to Reproduce

  1. Get package from '...'
  2. Then run '...'
  3. An error occurs.
# Put your Python code snippet here.

Versions

import astropy
astropy.system_info()
# Paste the result here

Activity

  1. pllim commented on Nov 25, 2025

    @pllim
  2. pllim commented on Nov 25, 2025

    @pllim
  3. mhvk commented on Nov 25, 2025

    @mhvk
    ContributorAuthor

    Yes, I was surprised by that deprecation warning too. But it is in the logs as well: https://github.com/astropy/astropy/actions/runs/19656142398/job/56292962904?pr=18986#step:10:187 -- yet it does not kill the job, so I'm not quite sure what is going on...

  4. pllim commented on Nov 26, 2025

    @pllim
    Member

    If the deprecation warning only shows up in oldest deps, it is either some unholy combo that @neutrinoceros is trying to smoke out in #18965 or tox weirdness. Since they are not failing the tests, I am not too worried unless we start to hear similar problems from users or downstream maintainers.

    As for the RuntimeError, I just cannot reproduce it but as I said, I also do not use tox locally.

  5. neutrinoceros commented on Nov 26, 2025

    @neutrinoceros
    Contributor

    note that the warnings already show on other PRs, so at least we know it's not caused by #18986.
    And indeed, it would be easier (or at least more reliable) to debug this after #18965 (and its parent issue #18782) are completed. I'm almost there by the way, so I'd encourage you to weigh in on remaining PRs linked there.

  6. neutrinoceros commented on Nov 26, 2025

    @neutrinoceros
    Contributor

    As to why it's not failing the test suite, it's not clear to me either. It looks like the warning is triggered at some point during pytest's collection phase, which usually still results in a crash, but maybe it's emmitted at a precise point where pytest is off guards and lets it through, and maybe that's a bug in pytest, but I don't know enough about how it's supposed to work to say that with certainty.

  7. pllim commented on Nov 26, 2025

    @pllim
    Member

    My suspicion is that pytest encountered one of the alldeps packages that still import the deprecated test runner from astropy in their init. I don't see how these warnings can come from astropy itself. As long as it is only oldest deps, I am not too worried.

  8. neutrinoceros commented on Nov 26, 2025

    @neutrinoceros
    Contributor

    But the example @mhvk included at the top doesn't seem to involve pytest at all though (at least, not directly)

  9. pllim commented on Nov 26, 2025

    @pllim
    Member

    Oh yeah... but I cannot reproduce any of the problems in the OP. 🤷‍♀️

  10. mhvk commented on Nov 26, 2025

    @mhvk
    ContributorAuthor

    @pllim - thanks! That makes sense for the test runner. As @neutrinoceros mentions, it does not solve the problem on top, but it does suggest a testable clue: I can try a tox with oldestdeps but not alldeps, and see if the warnings then disappear. If so, it is due to another dependency...

  11. neutrinoceros commented on Nov 29, 2025

    @neutrinoceros
    Contributor

    Finally coming around to this: I can reproduce the warnings with a single command

    ❯ uv run --resolution=lowest-direct -p3.11 --extra test --extra all python -c "from astropy.coordinates import Angle"
    WARNING: AstropyDeprecationWarning: The TestRunner class is deprecated and may be removed in a future version.
            Use pytest instead. [astropy.tests.runner]
    WARNING: AstropyDeprecationWarning: The TestRunnerBase class is deprecated and may be removed in a future version.
            Use pytest instead. [astropy.utils.decorators]
    

    will inquire

  12. neutrinoceros commented on Nov 29, 2025

    @neutrinoceros
    Contributor

    simply promoting warnings to errors with -Werror yields a useful tracevback

    ❯ uv run --resolution=lowest-direct -p3.11 --extra test --extra all python -c "from astropy.coordinates import Angle"
    
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/Users/clm/dev/orgs/astropy/astropy/astropy/coordinates/__init__.py", line 11, in <module>
        from .baseframe import *
      File "/Users/clm/dev/orgs/astropy/astropy/astropy/coordinates/baseframe.py", line 25, in <module>
        from astropy.table import QTable
      File "/Users/clm/dev/orgs/astropy/astropy/astropy/table/__init__.py", line 127, in <module>
        import asdf_astropy.io.connect
      File "/Users/clm/dev/orgs/astropy/astropy/.venv/lib/python3.11/site-packages/asdf_astropy/__init__.py", line 4, in <module>
        from ._astropy_init import *  # noqa: F403
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/Users/clm/dev/orgs/astropy/astropy/.venv/lib/python3.11/site-packages/asdf_astropy/_astropy_init.py", line 10, in <module>
        test = TestRunner.make_test_runner_in(Path(__file__).parent)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/Users/clm/dev/orgs/astropy/astropy/astropy/tests/runner.py", line 283, in make_test_runner_in
        runner = cls(path)
                 ^^^^^^^^^
      File "/Users/clm/dev/orgs/astropy/astropy/astropy/utils/decorators.py", line 141, in deprecated_func
        warnings.warn(message, category, stacklevel=2)
    astropy.utils.exceptions.AstropyDeprecationWarning: The TestRunner class is deprecated and may be removed in a future version.
            Use pytest instead.
  13. neutrinoceros commented on Nov 29, 2025

    @neutrinoceros
    Contributor

    so it's actually rather simple: asdf-astropy==0.7.0 is still using the TestRunner class. The following version, 0.8.0, doesn't. So the warning goes away if we bump the minimal requirement to 0.8.0:

    ❯ uv run --with "asdf-astropy>=0.8" --resolution=lowest-direct -p3.11 --extra test --extra all python -Werror -c "from astropy.coordinates import Angle"
    

    completes without error.
    Since the warning isn't blocking in CI, I don't think that's reason enough to bump now, and in any case, we'll have to make this bump when we remove the TestRunner class (at the latest). With this clarified, I don't believe any action is required anywhere, so I'll close this. Thanks for bringing it to my attention !

  14. mhvk commented on Nov 29, 2025

    @mhvk
    ContributorAuthor

    @neutrinoceros - does this also remove the errorwarning raised by Angle? (reopening until confirmed that it doesn't)

  15. reopened this on Nov 29, 2025
  16. neutrinoceros commented on Nov 29, 2025

    @neutrinoceros
    Contributor

    Ah, I missed that there were 2 different warnings. I just tried, but couldn't reproduce the other one yet, with main or with your branch checked out.

  17. mhvk commented on Nov 29, 2025

    @mhvk
    ContributorAuthor

    It is a very weird one, I'll see if I can still reproduce it. But it definitely caused failures before I silenced the warning.

  18. neutrinoceros commented on Nov 29, 2025

    @neutrinoceros
    Contributor

    I can't wait for oldestdeps builds to be reproducible

  19. neutrinoceros commented on Nov 29, 2025

    @neutrinoceros
    Contributor

    Whatever we decide to do with you PR, closing #18782 first would be a good idea.

  20. mhvk commented on Dec 3, 2025

    @mhvk
    ContributorAuthor

    Verified that the problem is still there even if one does not load alldeps, so it is just a numpy interaction (probably a rare bug that was fixed in the meantime). I don't really like the code in Angle.to_string() so will refactor it, ensuring no warning is emitted.

  21. jdavies-st commented on Oct 15, 2026

    @jdavies-st
    Contributor

    I ran into this while trying out a CI job that runs pyvo's tests against astropy main through the OpenAstronomy tox workflow: three tests in pyvo fail on x86_64 Linux.

    But the exact same tox job does not fail on pyvo's own CI. It uses actions/setup-python which installs Debian CPython, and does not see this. OpenAstronomy uses a uv-built CPython.

    Building on

    It seems to be x86_64 only. It doesn't reproduce on macOS or Linux on arm64.

    With released astropy 8.0.1 and numpy 2.5.4:

    SkyCoord(2, 4, unit="deg").to_string()
    

    with -W error:

    CPython 3.14.8 build x86_64 aarch64
    uv (python-build-standalone) RuntimeWarning OK
    Debian (python:3.14 Docker image) OK OK

    uv's 3.14.7 build on x86_64 warns too.

    I ran the aarch64 column above natively on my macOS laptop and the x86_64 column under Docker's x86_64 emulation. The x86_64 results match the GitHub Actions x86_64 runners, where the pyvo tests fail.

    To reproduce on x86_64 (the --platform flag only matters on a non-x86 host):

    docker run --rm --platform linux/amd64 python:3.14 bash -c '
    pip -q install uv
    for pref in only-managed only-system; do
      rm -rf /venv
      UV_PYTHON_PREFERENCE=$pref uv venv -q --python 3.14 /venv
      uv pip install -q --python /venv/bin/python "numpy==2.5.4" astropy
      /venv/bin/python -W error -c "from astropy.coordinates import SkyCoord; print(SkyCoord(2, 4, unit=\"deg\").to_string())"
    done'

    Output of the first pass (uv's build):

    Traceback (most recent call last):
      File "<string>", line 1, in <module>
        from astropy.coordinates import SkyCoord; print(SkyCoord(2, 4, unit="deg").to_string())
                                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
      File "/venv/lib/python3.14/site-packages/astropy/coordinates/sky_coordinate.py", line 893, in to_string
        f"{sph_coord.lon.to_string(**lonargs)}"
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
      File "/venv/lib/python3.14/site-packages/astropy/coordinates/angles/core.py", line 386, in to_string
        result = format_ufunc(self.to_value(unit))
      File "/venv/lib/python3.14/site-packages/numpy/lib/_function_base_impl.py", line 2530, in __call__
        return self._call_as_normal(*args, **kwargs)
               ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
      File "/venv/lib/python3.14/site-packages/numpy/lib/_function_base_impl.py", line 2523, in _call_as_normal
        return self._vectorize_call(func=func, args=vargs)
               ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
      File "/venv/lib/python3.14/site-packages/numpy/lib/_function_base_impl.py", line 2611, in _vectorize_call
        outputs = ufunc(*args, out=...)
    RuntimeWarning: invalid value encountered in do_format (vectorized)
    

    and the second (Debian build):

    2 4
    

    I suspect the Angle.to_string change from #19021 is probably a good fix for this - don't use np.vectorize.

  22. jdavies-st commented on Oct 15, 2026

    @jdavies-st
    Contributor

    Ah, but the solution in #19021 doesn't work for masked arrays. It converts it to unmasked. ☹️

    angle = Masked(Angle([1.0, 2.0], unit=u.deg), mask=[False, True])
    result = angle.to_string()
    assert isinstance(result, Masked)
    # AssertionError: False = isinstance(array(['1d00m00s', '2d00m00s'], dtype='<U8'), Masked)

    Maybe just

    with np.errstate(invalid="ignore"):
        result = ...<vectorized formating ufunc>...
    

    is the solution, given it is spurious depending on how CPython is built. I don't think a blanket invalid="ignore" there would hide anything else. do_format handles NaN before formatting, and there's no warning for +/- inf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions