diff --git a/CHANGES.rst b/CHANGES.rst
index 70cdfb1b..51a17b73 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,6 +4,8 @@
Enhancements and Fixes
----------------------
+- Support the flat representation of the MANGO observation dates (year, mjd, jd, iso) [#726]
+
- Add DEFAULT_JOB_POLL_TIMEOUT constant [#721]
- Pass session through to DatalinkService requests (#715)
@@ -12,7 +14,7 @@ Enhancements and Fixes
- Provide an API for SoftId-compliant management of the 'User-Agent'
header [#719]
-
+
Deprecations and Removals
-------------------------
diff --git a/pyvo/mivot/features/sky_coord_builder.py b/pyvo/mivot/features/sky_coord_builder.py
index c9713c72..2fa20308 100644
--- a/pyvo/mivot/features/sky_coord_builder.py
+++ b/pyvo/mivot/features/sky_coord_builder.py
@@ -89,17 +89,12 @@ def _get_time_instance(self, hk_field, besselian=False):
-----
MappingError: if the Time instance cannot be built for some reason
"""
- # Process complex type "mango:DateTime"
- if hk_field['dmtype'] == "mango:DateTime":
- representation = hk_field['representation']['value']
- timestamp = hk_field['dateTime']['value']
- # Process complex type "coords:epoch" used for the space frame equinox
- elif hk_field['dmtype'] == "coords:Epoch":
+ if hk_field['dmtype'] == "coords:Epoch":
representation = 'yr' if "unit" not in hk_field else hk_field.get("unit")
timestamp = hk_field['value']
# Process simple attribute
else:
- representation = hk_field.get("unit")
+ representation = hk_field.get("dmtype")
timestamp = hk_field.get("value")
if not representation or not timestamp:
@@ -124,15 +119,16 @@ def _build_time_instance(self, timestamp, representation, besselian=False):
timestamp: string or number
The timestamp must comply with the given representation
representation: string
- year, iso, ... (See MANGO primitive types derived from ivoa:timeStamp)
+ mango:year, mango:iso, mango:mjd, mango:jd
+ (See MANGO primitive types derived from ivoa:timeStamp)
besselian: boolean (optional)
Flag telling to use the besselain calendar. We assume it to only be
- relevant for FK5 frame
+ relevant for FK4 frame
returns
-------
Time instance or None
"""
- if representation in ("year", "yr", "y"):
+ if representation in ("mango:year", "yr", "y"):
# it the timestamp is numeric, we infer its format from the besselian flag
if isinstance(timestamp, numbers.Number):
return Time(f"{('B' if besselian else 'J')}{timestamp}",
@@ -159,10 +155,12 @@ def _build_time_instance(self, timestamp, representation, besselian=False):
return None
# in the following cases, the calendar (B or J) is given by the besselian flag
# We force to use the string representation to avoid breaking unit tests.
- elif representation in ("mjd", "jd", "iso"):
- time = Time(f"{timestamp}", format=representation)
+ elif representation in ("mango:mjd", "mango:jd", "mango:iso"):
+ astropyformat = representation.split(":")[1]
+ time = Time(f"{timestamp}", format=astropyformat)
return (Time(time.byear_str) if besselian else time)
+ print("================= 4")
return None
def _get_space_frame(self):
diff --git a/pyvo/mivot/tests/data/reference/mango_object.xml b/pyvo/mivot/tests/data/reference/mango_object.xml
index 8055aa3a..6fcf5cdc 100644
--- a/pyvo/mivot/tests/data/reference/mango_object.xml
+++ b/pyvo/mivot/tests/data/reference/mango_object.xml
@@ -186,10 +186,7 @@
-
-
-
-
+
diff --git a/pyvo/mivot/tests/data/simbad-cone-mivot.xml b/pyvo/mivot/tests/data/simbad-cone-mivot.xml
index b0987713..a2a11658 100644
--- a/pyvo/mivot/tests/data/simbad-cone-mivot.xml
+++ b/pyvo/mivot/tests/data/simbad-cone-mivot.xml
@@ -41,10 +41,7 @@
-
-
-
-
+
diff --git a/pyvo/mivot/tests/test_mango_annoter.py b/pyvo/mivot/tests/test_mango_annoter.py
index 6c5c38c7..58477f49 100644
--- a/pyvo/mivot/tests/test_mango_annoter.py
+++ b/pyvo/mivot/tests/test_mango_annoter.py
@@ -15,6 +15,7 @@
from pyvo.mivot.version_checker import check_astropy_version
from pyvo.mivot.utils.xml_utils import XmlUtils
from pyvo.mivot.writer.instances_from_models import InstancesFromModels
+from pyvo.mivot.utils.exceptions import MappingError
# Enable MIVOT-specific features in the pyvo library
@@ -70,6 +71,17 @@ def add_color(builder):
builder.add_mango_color(filter_ids=filter_ids, mapping=mapping, semantics=semantics)
+@pytest.mark.filterwarnings("ignore:root:::")
+def add_color_without_definition(builder):
+
+ filter_ids = {"high": "GAIA/GAIA3.Grp/AB", "low": "GAIA/GAIA3.Grvs/AB"}
+ mapping = {"value": 8.76,
+ "error": {"class": "PErrorAsym1D", "low": 1, "high": 3}
+ }
+ semantics = {"description": "very nice color", "uri": "vocabulary#term", "label": "term"}
+ builder.add_mango_color(filter_ids=filter_ids, mapping=mapping, semantics=semantics)
+
+
@pytest.mark.filterwarnings("ignore:root:::")
def add_photometry(builder):
photcal_id = "GAIA/GAIA3.Grvs/AB"
@@ -82,13 +94,13 @@ def add_photometry(builder):
builder.add_mango_brightness(photcal_id=photcal_id, mapping=mapping, semantics=semantics)
-def add_epoch_positon(builder):
+def add_epoch_position(builder):
frames = {"spaceSys": {"spaceRefFrame": "ICRS", "refPosition": 'BARYCENTER', "equinox": None},
"timeSys": {"timescale": "TCB", "refPosition": 'BARYCENTER'}}
mapping = {"longitude": "_RAJ2000", "latitude": "_DEJ2000",
"pmLongitude": "pmRA", "pmLatitude": "pmDE",
"parallax": "Plx", "radialVelocity": "RV",
- "obsDate": {"representation": "mjd", "dateTime": 579887.6},
+ "obsDate": {"dmtype": "mango:mjd", "value": 579887.6},
"correlations": {"isCovariance": True,
"longitudeLatitude": "RADEcor",
"latitudePmLongitude": "DEpmRAcor", "latitudePmLatitude": "DEpmDEcor",
@@ -109,6 +121,19 @@ def add_epoch_positon(builder):
builder.add_mango_epoch_position(frames=frames, mapping=mapping, semantics=semantics)
+def add_epoch_position_with_wrong_date(builder):
+ frames = {"spaceSys": {"spaceRefFrame": "ICRS", "refPosition": 'BARYCENTER', "equinox": None},
+ "timeSys": {"timescale": "TCB", "refPosition": 'BARYCENTER'}}
+ mapping = {"longitude": "_RAJ2000", "latitude": "_DEJ2000",
+ "obsDate": {"representation": "mango:mjd", "value": 579887.6},
+ }
+ semantics = {"description": "6 parameters position",
+ "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#astronomical-location",
+ "label": "Astronomical location"}
+
+ builder.add_mango_epoch_position(frames=frames, mapping=mapping, semantics=semantics)
+
+
@pytest.mark.usefixtures("mocked_fps_grvs", "mocked_fps_grp")
@pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+")
def test_all_properties():
@@ -151,12 +176,19 @@ def test_all_properties():
})
add_color(builder)
add_photometry(builder)
- add_epoch_positon(builder)
+ add_epoch_position(builder)
builder.pack_into_votable(schema_check=False)
assert XmlUtils.strip_xml(builder._annotation.mivot_block) == (
XmlUtils.strip_xml(get_pkg_data_contents("data/reference/mango_object.xml"))
)
+ builder = InstancesFromModels(votable, dmid="DR3Name")
+ with pytest.raises(MappingError):
+ add_epoch_position_with_wrong_date(builder)
+
+ with pytest.raises(MappingError):
+ add_color_without_definition(builder)
+
@pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+")
def test_extraction_from_votable_header():
diff --git a/pyvo/mivot/tests/test_sky_coord_builder.py b/pyvo/mivot/tests/test_sky_coord_builder.py
index f9bf98bd..7687a55c 100644
--- a/pyvo/mivot/tests/test_sky_coord_builder.py
+++ b/pyvo/mivot/tests/test_sky_coord_builder.py
@@ -47,7 +47,7 @@
"ref": "pmDE",
},
"obsDate": {
- "dmtype": "ivoa:RealQuantity",
+ "dmtype": "mango:year",
"value": 1991.25,
"unit": "yr",
"ref": None,
@@ -100,7 +100,7 @@
"ref": "parallax",
},
"obsDate": {
- "dmtype": "ivoa:RealQuantity",
+ "dmtype": "mango:year",
"value": 1991.25,
"unit": "yr",
"ref": None,
@@ -292,13 +292,13 @@ def test_time_representation():
"""
# work with a copy to not alter other test functions
mydict = deepcopy(vizier_equin_dict)
- mydict["obsDate"]["unit"] = "mjd"
+ mydict["obsDate"]["dmtype"] = "mango:mjd"
mivot_instance = MivotInstance(**mydict)
scb = SkyCoordBuilder(mivot_instance)
scoo = scb.build_sky_coord()
assert scoo.obstime.jyear_str == "J1864.331"
- mydict["obsDate"]["unit"] = "jd"
+ mydict["obsDate"]["dmtype"] = "mango:jd"
mydict["obsDate"]["value"] = "2460937.36"
mivot_instance = MivotInstance(**mydict)
scb = SkyCoordBuilder(mivot_instance)
@@ -306,10 +306,33 @@ def test_time_representation():
assert scoo.obstime.jyear_str == "J2025.715"
mydict = deepcopy(vizier_equin_dict)
- mydict["obsDate"]["unit"] = "iso"
- mydict["obsDate"]["dmtype"] = "ivoa:string"
+ mydict["obsDate"]["dmtype"] = "mango:iso"
mydict["obsDate"]["value"] = "2025-05-03"
mivot_instance = MivotInstance(**mydict)
scb = SkyCoordBuilder(mivot_instance)
scoo = scb.build_sky_coord()
assert scoo.obstime.jyear_str == "J2025.335"
+
+ mydict = deepcopy(vizier_equin_dict)
+ mydict["obsDate"]["dmtype"] = "mango:year"
+ mydict["obsDate"]["value"] = "B356"
+ mivot_instance = MivotInstance(**mydict)
+ scb = SkyCoordBuilder(mivot_instance)
+ with pytest.raises(MappingError):
+ scb.build_sky_coord()
+
+ mydict = deepcopy(vizier_equin_dict)
+ mydict["obsDate"]["dmtype"] = "mango:year"
+ mydict["obsDate"]["value"] = "turlutu"
+ mivot_instance = MivotInstance(**mydict)
+ scb = SkyCoordBuilder(mivot_instance)
+ with pytest.raises(MappingError):
+ scb.build_sky_coord()
+
+ mydict = deepcopy(vizier_equin_dict)
+ mydict["obsDate"]["dmtype"] = "turlututu"
+ mydict["obsDate"]["value"] = "turlututu"
+ mivot_instance = MivotInstance(**mydict)
+ scb = SkyCoordBuilder(mivot_instance)
+ with pytest.raises(MappingError):
+ scb.build_sky_coord()
diff --git a/pyvo/mivot/writer/mango_object.py b/pyvo/mivot/writer/mango_object.py
index 617cb0ac..423ba947 100644
--- a/pyvo/mivot/writer/mango_object.py
+++ b/pyvo/mivot/writer/mango_object.py
@@ -7,7 +7,7 @@
from pyvo.mivot.utils.mivot_utils import MivotUtils
from pyvo.mivot.writer.instance import MivotInstance
from pyvo.mivot.glossary import (
- IvoaType, ModelPrefix, Roles, CoordSystems)
+ IvoaType, ModelPrefix, Roles)
class Property(MivotInstance):
@@ -127,36 +127,6 @@ def _add_epoch_position_errors(self, **errors):
mapping))
return err_instance
- def _add_epoch_position_epoch(self, **mapping):
- """
- Private method building and returning the observation date (DateTime) of the EpohPosition.
-
- Parameters
- ----------
- mapping: dict(representation, datetime)
- Mapping of the DateTime fields
-
- Returns
- -------
- `Property`
- The EpochPosition observation date instance
- """
- datetime_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:DateTime",
- dmrole=f"{ModelPrefix.mango}:EpochPosition.obsDate")
-
- representation = mapping.get("representation")
- value = mapping["dateTime"]
- if representation not in CoordSystems.time_formats:
- raise MappingError(f"epoch representation {representation} not supported. "
- f"Take on of {CoordSystems.time_formats}")
- datetime_instance.add_attribute(IvoaType.string,
- f"{ModelPrefix.mango}:DateTime.representation",
- value=MivotUtils.as_literal(representation))
- datetime_instance.add_attribute(IvoaType.datetime,
- f"{ModelPrefix.mango}:DateTime.dateTime",
- value=value)
- return datetime_instance
-
def add_epoch_position(self, space_frame_id, time_frame_id, mapping, semantics):
"""
Add an ``EpochPosition`` instance to the properties of the current ``MangoObject``.
@@ -184,7 +154,11 @@ def add_epoch_position(self, space_frame_id, time_frame_id, mapping, semantics):
MivotUtils.populate_instance(ep_instance, "EpochPosition",
mapping, self._table, IvoaType.RealQuantity)
if "obsDate" in mapping:
- ep_instance.add_instance(self._add_epoch_position_epoch(**mapping["obsDate"]))
+ if "dmtype" not in mapping["obsDate"] or "value" not in mapping["obsDate"]:
+ raise MappingError("obsDate requires both 'dmtype' and 'value' keys")
+ ep_instance.add_attribute(dmtype=mapping["obsDate"]["dmtype"],
+ dmrole="mango:EpochPosition.obsDate",
+ value=mapping["obsDate"]["value"])
if "correlations" in mapping:
ep_instance.add_instance(self._add_epoch_position_correlations(**mapping["correlations"]))
if "errors" in mapping: