Describe the bug
|
global _ignore_sun_motion |
|
|
|
old_ignore_sun_motion = _ignore_sun_motion # nominally False |
|
|
|
if not old_ignore_sun_motion: |
|
log.debug("Ignoring the motion of the center of the Sun for transformations") |
|
_ignore_sun_motion = True |
|
yield |
We set up an HTTP front end for coordinate transformations which uses sunpy for the transformations. We started randomly hitting this error:
File "/home/nonroot/.conda/envs/coordinator/lib/python3.13/site-packages/sunpy/coordinates/screens.py", line 42, in __exit__
raise RuntimeError(f"Cannot remove {self._context_name} from tracking stack because {removed} is last active.")
RuntimeError: Cannot remove sunpy.coordinates.screens.SphericalScreen from tracking stack because sunpy.coordinates._transformations.transform_with_sun_center is last active.
After investigating it seems that since each request is running on a thread, the state of the context manager ends up shared between threads since it's tracked at the module level, and so entering/exiting the context managers out of order causes this error.
To Reproduce
This script demonstrates the issue by starting 2 threads that use context managers but exit at different times.
"""
Reproduction script for SunPy coordinate tracking stack error using threading.
This script demonstrates the RuntimeError that occurs when multiple threads
interleave their use of SunPy coordinate context managers, causing the
tracking stack to become corrupted.
"""
import threading
import time
import astropy.units as u
from astropy.coordinates import SkyCoord
from sunpy.coordinates import HeliographicStonyhurst
from sunpy.coordinates.screens import SphericalScreen
from sunpy.coordinates import transform_with_sun_center
def run_spherical_screen():
"""
Thread 1: Enter SphericalScreen, delay, then exit.
"""
print("[Thread 1] Starting...")
# Create a coordinate
coord = SkyCoord(
0 * u.deg,
0 * u.deg,
1 * u.AU,
frame=HeliographicStonyhurst,
obstime='2023-01-01'
)
print("[Thread 1] Entering SphericalScreen")
with SphericalScreen(coord):
print("[Thread 1] Inside SphericalScreen")
time.sleep(0.5) # Delay to allow thread 2 to enter transform_with_sun_center
print("[Thread 1] About to exit SphericalScreen")
print("[Thread 1] Exited SphericalScreen")
def run_transform_with_sun_center():
"""
Thread 2: Wait a bit, enter transform_with_sun_center, delay, then exit.
This will interleave with thread 1's operation.
"""
print("[Thread 2] Starting...")
time.sleep(0.2) # Wait for thread 1 to enter SphericalScreen first
print("[Thread 2] Entering transform_with_sun_center")
with transform_with_sun_center():
print("[Thread 2] Inside transform_with_sun_center")
time.sleep(0.5) # Stay inside while thread 1 tries to exit
print("[Thread 2] About to exit transform_with_sun_center")
print("[Thread 2] Exited transform_with_sun_center")
def reproduce_error():
"""
Run two threads that will interleave their context manager usage,
causing the tracking stack error.
"""
print("Starting threads to reproduce tracking stack error...\n")
t1 = threading.Thread(target=run_spherical_screen, name="SphericalScreen")
t2 = threading.Thread(target=run_transform_with_sun_center, name="TransformWithSunCenter")
t1.start()
t2.start()
t1.join()
t2.join()
print("\nThreads completed")
if __name__ == "__main__":
print("Attempting to reproduce SunPy coordinate tracking stack error...")
print("This uses threading to create a race condition in the context manager stack.\n")
print("=" * 70)
print()
try:
reproduce_error()
except RuntimeError as e:
print()
print("=" * 70)
print("\nSuccessfully reproduced the error!")
print(f"Error message: {e}")
Screenshots
No response
System Details
==============================
sunpy Installation Information
==============================
General
#######
OS: Mac OS 26.2
Arch: 64bit, (arm)
sunpy: 7.1.0
Installation path: /Users/dgarciab/PostMabel/fastapi-test/venv/lib/python3.14/site-packages/sunpy-7.1.0.dist-info
Required Dependencies
#####################
astropy: 7.2.0
fsspec: 2026.1.0
numpy: 2.4.2
packaging: 26.0
parfive: 2.3.1
pyerfa: 2.0.1.5
requests: 2.32.5
Optional Dependencies
#####################
asdf-astropy: Missing asdf-astropy>=0.5.0; extra == "asdf" or "asdf" or "asdf" or "asdf" or "asdf"
beautifulsoup4: Missing beautifulsoup4>=4.13.1; extra == "net" or "net" or "net" or "net" or "net"
cdflib: Missing cdflib>=1.3.2; extra == "timeseries" or "timeseries" or "timeseries" or "timeseries" or "timeseries"
contourpy: Missing contourpy>=1.1.0; extra == "map" or "map" or "map" or "map" or "map"
drms: Missing drms>=0.7.1; extra == "net" or "net" or "net" or "net" or "net"
glymur: Missing glymur>=0.13.0; extra == "jpeg2000" or "jpeg2000" or "jpeg2000" or "jpeg2000"
h5netcdf: Missing h5netcdf>=1.2.0; extra == "timeseries" or "timeseries" or "timeseries" or "timeseries" or "timeseries"
h5py: Missing h5py>=3.10.0; extra == "timeseries" or "timeseries" or "timeseries" or "timeseries" or "timeseries"
lxml: Missing lxml>=5.0.1; extra == "jpeg2000" or "jpeg2000" or "jpeg2000" or "jpeg2000"
matplotlib: Missing matplotlib>=3.8.0; extra == "map" or "timeseries" or "visualization" or "timeseries" or "timeseries" or "timeseries" or "timeseries"
mpl-animators: Missing mpl-animators>=1.2.0; extra == "map" or "visualization" or "map" or "map" or "map" or "map"
opencv-python: Missing opencv-python>=4.8.0.74; extra == "opencv" or "opencv" or "opencv" or "opencv"
pandas: Missing pandas>=2.2.0; extra == "timeseries" or "timeseries" or "timeseries" or "timeseries" or "timeseries"
python-dateutil: Missing python-dateutil>=2.9.0; extra == "net" or "net" or "net" or "net" or "net"
reproject: Missing reproject>=0.13.0; extra == "map" or "map" or "map" or "map" or "map"
scipy: Missing scipy>=1.12.0; extra == "image" or "map" or "image" or "image" or "image" or "image"
spiceypy: Missing spiceypy>=6.0.0; extra == "spice" or "spice" or "spice" or "spice"
tqdm: 4.67.2
zeep: Missing zeep>=4.3.0; extra == "net" or "net" or "net" or "net" or "net"
Installation method
pip
Describe the bug
sunpy/sunpy/coordinates/_transformations.py
Lines 131 to 138 in 0c8a86e
We set up an HTTP front end for coordinate transformations which uses sunpy for the transformations. We started randomly hitting this error:
After investigating it seems that since each request is running on a thread, the state of the context manager ends up shared between threads since it's tracked at the module level, and so entering/exiting the context managers out of order causes this error.
To Reproduce
This script demonstrates the issue by starting 2 threads that use context managers but exit at different times.
Screenshots
No response
System Details
Installation method
pip