Skip to content

Commit 324f451

Browse files
authored
Use pytest-remotedata for offline/online test split (#211)
1 parent bd8ecdc commit 324f451

10 files changed

Lines changed: 555 additions & 55 deletions

File tree

.coveragerc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ omit =
44
sunpy_soar/*setup_package*
55
sunpy_soar/extern/*
66
sunpy_soar/version*
7+
sunpy_soar/_dev/*
8+
*/sunpy_soar/_dev/*
79
*/sunpy_soar/conftest.py
810
*/sunpy_soar/*setup_package*
911
*/sunpy_soar/extern/*

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ jobs:
6565
toxdeps: tox-pypi-filter
6666
posargs: -n auto
6767
envs: |
68-
- linux: py314
69-
- windows: py312
70-
- macos: py312
71-
- linux: py312-oldestdeps
72-
- linux: py314-devdeps
68+
- linux: py314-online
69+
- windows: py312-online
70+
- macos: py312-online
71+
- linux: py312-oldestdeps-online
72+
- linux: py314-devdeps-online
7373
secrets:
7474
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
7575

docs/dev_guide/query.rst

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,13 @@ Using the example below,
3131
<sunpy.net.fido_factory.UnifiedResponse object at ...>
3232
Results from 1 Provider:
3333
<BLANKLINE>
34-
680 Results from the SOARClient:
34+
... Results from the SOARClient:
3535
<BLANKLINE>
36-
Instrument Data product Level Start time End time Filesize SOOP Name
36+
Instrument Data product Level Start time End time Filesize SOOP Name Sensor
3737
Mbyte
38-
---------- ------------------- ----- ----------------------- ----------------------- -------- ---------
39-
RPW rpw-tds-surv-hist2d L2 2022-10-09 00:00:00.000 2022-10-10 00:00:00.000 0.084 none
38+
---------- ------------------- ----- ----------------------- ----------------------- -------- --------- ------
39+
RPW rpw-tds-surv-hist2d L2 2022-10-09 00:00:00.000 2022-10-10 00:00:00.000 0.084 none TDS
4040
...
41-
<BLANKLINE>
42-
<BLANKLINE>
4341
4442
Here the query's "REQUEST" type to "doQueryFilteredByDistance", which is a special method that filters the entire database based on the specified distance value.
4543

docs/how_to/wavelength.rst

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,14 @@ When a single wavelength is provided it is interpreted as the wavelength.
3030
<sunpy.net.fido_factory.UnifiedResponse object at ...>
3131
Results from 1 Provider:
3232
<BLANKLINE>
33-
8 Results from the SOARClient:
33+
... Results from the SOARClient:
3434
<BLANKLINE>
3535
Instrument Data product Level Start time End time Filesize SOOP Name Detector Wavelength
3636
Mbyte
3737
---------- -------------- ----- ----------------------- ----------------------- -------- --------- -------- ----------
3838
METIS metis-uv-image L2 2023-02-01 01:00:48.690 2023-02-01 01:11:46.866 0.85 none UVD 121.6
39-
METIS metis-uv-image L2 2023-02-01 01:30:48.680 2023-02-01 01:41:45.540 0.85 none UVD 121.6
40-
METIS metis-uv-image L2 2023-02-01 02:00:48.671 2023-02-01 02:11:44.213 12.64 none UVD 121.6
41-
METIS metis-uv-image L2 2023-02-01 02:30:48.661 2023-02-01 02:41:42.887 12.64 none UVD 121.6
42-
METIS metis-uv-image L2 2023-02-01 03:00:48.652 2023-02-01 03:11:41.560 12.64 none UVD 121.6
43-
METIS metis-uv-image L2 2023-02-01 03:30:48.643 2023-02-01 03:41:40.233 12.64 none UVD 121.6
44-
METIS metis-uv-image L2 2023-02-01 04:00:48.633 2023-02-01 04:11:38.907 12.64 none UVD 121.6
45-
METIS metis-uv-image L2 2023-02-01 04:30:38.163 2023-02-01 04:40:37.625 12.64 none UVD 121.6
46-
<BLANKLINE>
47-
<BLANKLINE>
39+
...
40+
4841
4942
For instruments EUI, METIS and SOLOHI passing a range of Wavelength
5043
===================================================================
@@ -59,32 +52,10 @@ When a range of wavelength is provided, it is interpreted as the wavemin and wav
5952
<sunpy.net.fido_factory.UnifiedResponse object at ...>
6053
Results from 1 Provider:
6154
<BLANKLINE>
62-
64 Results from the SOARClient:
55+
... Results from the SOARClient:
6356
<BLANKLINE>
6457
Instrument Data product Level Start time End time Filesize SOOP Name Detector Wavelength
6558
Mbyte
6659
---------- ------------------ ----- ----------------------- ----------------------- -------- --------- -------- ----------
6760
METIS metis-vl-tb L2 2023-02-01 01:00:00.147 2023-02-01 01:24:37.923 12.64 none VLD 610.0
68-
METIS metis-vl-stokes L2 2023-02-01 01:00:00.147 2023-02-01 01:24:37.923 21.067 none VLD 610.0
69-
METIS metis-vl-pb L2 2023-02-01 01:00:00.147 2023-02-01 01:24:37.923 12.64 none VLD 610.0
70-
METIS metis-vl-image L2 2023-02-01 01:00:00.147 2023-02-01 01:23:05.525 12.643 none VLD 610.0
71-
METIS metis-vl-pol-angle L2 2023-02-01 01:00:00.147 2023-02-01 01:24:37.923 12.64 none VLD 610.0
72-
METIS metis-vl-image L2 2023-02-01 01:00:30.944 2023-02-01 01:23:36.322 12.643 none VLD 610.0
73-
METIS metis-vl-image L2 2023-02-01 01:01:01.741 2023-02-01 01:24:07.127 12.643 none VLD 610.0
74-
METIS metis-vl-image L2 2023-02-01 01:01:32.538 2023-02-01 01:24:37.922 12.643 none VLD 610.0
75-
METIS metis-vl-stokes L2 2023-02-01 01:30:00.150 2023-02-01 01:54:37.922 21.067 none VLD 610.0
76-
METIS metis-vl-pol-angle L2 2023-02-01 01:30:00.150 2023-02-01 01:54:37.922 12.64 none VLD 610.0
77-
... ... ... ... ... ... ... ... ...
78-
METIS metis-vl-image L2 2023-02-01 04:01:01.774 2023-02-01 04:24:07.158 50.388 none VLD 610.0
79-
METIS metis-vl-image L2 2023-02-01 04:01:32.571 2023-02-01 04:24:37.955 50.388 none VLD 610.0
80-
METIS metis-vl-pol-angle L2 2023-02-01 04:30:00.201 2023-02-01 04:54:37.981 50.388 none VLD 610.0
81-
METIS metis-vl-stokes L2 2023-02-01 04:30:00.201 2023-02-01 04:54:37.981 83.981 none VLD 610.0
82-
METIS metis-vl-tb L2 2023-02-01 04:30:00.201 2023-02-01 04:54:37.981 50.388 none VLD 610.0
83-
METIS metis-vl-pb L2 2023-02-01 04:30:00.201 2023-02-01 04:54:37.981 50.388 none VLD 610.0
84-
METIS metis-vl-image L2 2023-02-01 04:30:00.201 2023-02-01 04:53:05.585 50.388 none VLD 610.0
85-
METIS metis-vl-image L2 2023-02-01 04:30:30.999 2023-02-01 04:53:36.383 50.388 none VLD 610.0
86-
METIS metis-vl-image L2 2023-02-01 04:31:01.796 2023-02-01 04:54:07.184 50.388 none VLD 610.0
87-
METIS metis-vl-image L2 2023-02-01 04:31:32.593 2023-02-01 04:54:37.979 50.388 none VLD 610.0
88-
Length = 64 rows
89-
<BLANKLINE>
90-
<BLANKLINE>
61+
...

examples/searching_with_sensor.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""
2-
=============================================================
3-
Searching for EPD/EPT data with the `a.soar.Sensor` attribute
4-
=============================================================
2+
===============================================================
3+
Searching for EPD/EPT data with the ``a.soar.Sensor`` attribute
4+
===============================================================
55
66
This example demonstrates how to search and download Solar Orbiter data for a specific instrument sensor.
7-
Here, we will build a query for EPD data, specifically from the EPT sensor using ``a.soar.Sensor``.
7+
Here, we will build a query for EPD data, specifically from the EPT sensor using `a.soar.Sensor <sunpy_soar.attrs.Sensor>`.
88
"""
99

1010
import sunpy.net.attrs as a

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ tests-only = [
3333
"pytest-cov",
3434
"pytest-doctestplus",
3535
"pytest",
36+
"pytest-remotedata",
3637
]
3738
tests = [
3839
"sunpy_soar[tests-deps,tests-only]",

pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ addopts =
2222
--doctest-rst
2323
-p no:unraisableexception
2424
-p no:threadexception
25+
markers =
26+
remote_data: marks this test function as needing remote data.
27+
remote_data_strict = true
2528
filterwarnings =
2629
# Turn all warnings into errors so they do not pass silently.
2730
error

sunpy_soar/tests/test_attrs.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import astropy.units as u
2+
import pytest
3+
import sunpy.net.attrs as a
4+
from sunpy.util.exceptions import SunpyUserWarning
5+
6+
from sunpy_soar._attrs import SOOP, Distance, Product, Sensor, walker
7+
8+
9+
def _apply(attr):
10+
"""Apply a single attr via the walker and return the resulting params list."""
11+
params = []
12+
walker.apply(attr, params)
13+
return params
14+
15+
16+
def test_time():
17+
attr = a.Time("2023-01-15 06:30:00", "2023-01-16 12:45:00")
18+
params = _apply(attr)
19+
assert len(params) == 1
20+
assert params[0] == "begin_time>='2023-01-15 06:30:00' AND begin_time<='2023-01-16 12:45:00'"
21+
22+
23+
def test_level_from_int():
24+
"""Integer level should be converted to 'L<n>' string."""
25+
params = _apply(a.Level(2))
26+
assert params == ["level='L2'"]
27+
28+
29+
def test_level_from_string():
30+
"""String levels should be uppercased."""
31+
params = _apply(a.Level("l1"))
32+
assert params == ["level='L1'"]
33+
34+
35+
def test_level_low_latency():
36+
"""Low-latency level strings should pass through uppercased."""
37+
params = _apply(a.Level("LL02"))
38+
assert params == ["level='LL02'"]
39+
40+
41+
def test_level_invalid_warns():
42+
"""An unrecognised level should emit a SunpyUserWarning."""
43+
with pytest.warns(SunpyUserWarning, match="level not in list of allowed levels"):
44+
_apply(a.Level("L9"))
45+
46+
47+
def test_instrument():
48+
params = _apply(a.Instrument("EUI"))
49+
assert params == ["instrument='EUI'"]
50+
51+
52+
def test_product():
53+
params = _apply(Product("eui-fsi174-image"))
54+
assert params == ["descriptor='eui-fsi174-image'"]
55+
56+
57+
def test_provider():
58+
params = _apply(a.Provider("SOAR"))
59+
assert params == ["provider='SOAR'"]
60+
61+
62+
def test_soop():
63+
params = _apply(SOOP("r_small_mres_mcad_ar_long_term"))
64+
assert params == ["soop_name='r_small_mres_mcad_ar_long_term'"]
65+
66+
67+
def test_detector():
68+
params = _apply(a.Detector("HRI_EUV"))
69+
assert params == ["Detector='HRI_EUV'"]
70+
71+
72+
def test_sensor():
73+
params = _apply(Sensor("ept"))
74+
assert params == ["Sensor='ept'"]
75+
76+
77+
def test_wavelength():
78+
params = _apply(a.Wavelength(304 * u.AA, 304 * u.AA))
79+
assert len(params) == 1
80+
assert params[0] == "Wavemin='304.0' AND Wavemax='304.0'"
81+
82+
83+
def test_wavelength_range():
84+
params = _apply(a.Wavelength(171 * u.AA, 304 * u.AA))
85+
assert params[0] == "Wavemin='171.0' AND Wavemax='304.0'"
86+
87+
88+
def test_distance():
89+
params = _apply(Distance(0.3 * u.AU, 0.5 * u.AU))
90+
assert len(params) == 1
91+
assert params[0] == "DISTANCE(0.3,0.5)"
92+
93+
94+
def test_distance_out_of_bounds_warns():
95+
"""Distance values outside 0.28-1.0 AU should emit a warning."""
96+
with pytest.warns(SunpyUserWarning, match="Distance values must be within the range"):
97+
_apply(Distance(0.1 * u.AU, 0.5 * u.AU))
98+
99+
100+
def test_distance_max_out_of_bounds_warns():
101+
"""Only the max being out of bounds should also warn."""
102+
with pytest.warns(SunpyUserWarning, match="Distance values must be within the range"):
103+
_apply(Distance(0.3 * u.AU, 1.5 * u.AU))
104+
105+
106+
def test_and_applier():
107+
"""AttrAnd applier should recurse and collect all sub-attr params."""
108+
compound = a.Instrument("EUI") & a.Level(1) & Product("eui-fsi174-image")
109+
params = _apply(compound)
110+
assert "instrument='EUI'" in params
111+
assert "level='L1'" in params
112+
assert "descriptor='eui-fsi174-image'" in params
113+
assert len(params) == 3
114+
115+
116+
def test_create_from_single_attr():
117+
"""A single DataAttr should produce a list containing one sub-list."""
118+
result = walker.create(a.Instrument("EUI"))
119+
assert len(result) == 1
120+
assert result == [["instrument='EUI'"]]
121+
122+
123+
def test_create_from_and():
124+
"""An AND of attrs should produce a single sub-list with all params."""
125+
query = a.Instrument("EUI") & a.Level(2)
126+
result = walker.create(query)
127+
assert len(result) == 1
128+
assert "instrument='EUI'" in result[0]
129+
assert "level='L2'" in result[0]
130+
131+
132+
def test_create_from_or():
133+
"""An OR should produce multiple sub-lists, one per branch."""
134+
query = a.Instrument("EUI") | a.Instrument("STIX")
135+
result = walker.create(query)
136+
assert len(result) == 2
137+
assert result[0] == [["instrument='EUI'"]]
138+
assert result[1] == [["instrument='STIX'"]]
139+
140+
141+
def test_create_from_compound_or_and():
142+
"""OR of two AND branches should produce two sub-lists."""
143+
query = (a.Instrument("EUI") & a.Level(1)) | (a.Instrument("STIX") & a.Level(2))
144+
result = walker.create(query)
145+
assert len(result) == 2
146+
# Each branch is a list of one sub-list
147+
eui_params = result[0][0]
148+
stix_params = result[1][0]
149+
assert "instrument='EUI'" in eui_params
150+
assert "level='L1'" in eui_params
151+
assert "instrument='STIX'" in stix_params
152+
assert "level='L2'" in stix_params
153+
154+
155+
def test_lowercase():
156+
"""Product value should always be lowercased."""
157+
p = Product("EUI-FSI174-IMAGE")
158+
assert p.value == "eui-fsi174-image"
159+
160+
161+
def test_already_lowercase():
162+
p = Product("eui-fsi174-image")
163+
assert p.value == "eui-fsi174-image"
164+
165+
166+
def test_mixed_case():
167+
p = Product("Eui-Fsi174-Image")
168+
assert p.value == "eui-fsi174-image"
169+
170+
171+
def test_converts_km_to_au():
172+
"""Distance should convert km inputs to AU."""
173+
d = Distance(0.5 * u.AU.to(u.km) * u.km, 0.6 * u.AU.to(u.km) * u.km)
174+
assert u.isclose(d.min, 0.5 * u.AU)
175+
assert u.isclose(d.max, 0.6 * u.AU)
176+
177+
178+
def test_au_passthrough():
179+
"""AU inputs should be stored directly."""
180+
d = Distance(0.3 * u.AU, 0.4 * u.AU)
181+
assert u.isclose(d.min, 0.3 * u.AU)
182+
assert u.isclose(d.max, 0.4 * u.AU)
183+
184+
185+
def test_non_scalar_raises():
186+
"""Non-scalar quantities should raise ValueError."""
187+
with pytest.raises(ValueError, match="scalar"):
188+
Distance([0.3, 0.4] * u.AU, 0.5 * u.AU)
189+
190+
191+
def test_non_scalar_max_raises():
192+
with pytest.raises(ValueError, match="scalar"):
193+
Distance(0.3 * u.AU, [0.4, 0.5] * u.AU)
194+
195+
196+
def test_collides_with_same_class():
197+
d1 = Distance(0.3 * u.AU, 0.4 * u.AU)
198+
d2 = Distance(0.5 * u.AU, 0.6 * u.AU)
199+
assert d1.collides(d2) is True
200+
201+
202+
def test_does_not_collide_with_other_type():
203+
d = Distance(0.3 * u.AU, 0.4 * u.AU)
204+
assert d.collides(a.Time("2023-01-01", "2023-01-02")) is False

0 commit comments

Comments
 (0)