Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -12,7 +14,7 @@ Enhancements and Fixes

- Provide an API for SoftId-compliant management of the 'User-Agent'
header [#719]


Deprecations and Removals
-------------------------
Expand Down
22 changes: 10 additions & 12 deletions pyvo/mivot/features/sky_coord_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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}",
Expand All @@ -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):
Expand Down
5 changes: 1 addition & 4 deletions pyvo/mivot/tests/data/reference/mango_object.xml
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,7 @@
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.pmLatitude" unit="mas / yr" ref="pmDE"/>
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.parallax" unit="mas" ref="Plx"/>
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.radialVelocity" unit="km / s" ref="RV"/>
<INSTANCE dmtype="mango:DateTime" dmrole="mango:EpochPosition.obsDate">
<ATTRIBUTE dmtype="ivoa:string" dmrole="mango:DateTime.representation" value="mjd"/>
<ATTRIBUTE dmtype="ivoa:datatime" dmrole="mango:DateTime.dateTime" value="579887.6"/>
</INSTANCE>
<ATTRIBUTE dmtype="mango:mjd" dmrole="mango:EpochPosition.obsDate" value="579887.6"/>
<INSTANCE dmtype="mango:EpochPositionCorrelations" dmrole="mango:EpochPosition.correlations">
<ATTRIBUTE dmtype="ivoa:boolean" dmrole="mango:EpochPositionCorrelations.isCovariance" value="True"/>
<ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.longitudeLatitude" ref="RADEcor"/>
Expand Down
5 changes: 1 addition & 4 deletions pyvo/mivot/tests/data/simbad-cone-mivot.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.pmLatitude" unit="mas / yr" ref="pmdec"/>
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.parallax" unit="mas" ref="plx_value"/>
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.radialVelocity" unit="km / s" ref="rvz_radvel"/>
<INSTANCE dmrole="mango:EpochPosition.obsDate" dmtype="mango:DateTime">
<ATTRIBUTE dmrole="mango:DateTime.representation" dmtype="ivoa:string" value="year"/>
<ATTRIBUTE dmrole="mango:DateTime.dateTime" dmtype="ivoa:datetime" value="2000" unit="y"/>
</INSTANCE>
<ATTRIBUTE dmrole="mango:EpochPosition.obsDate" dmtype="mango:year" value="2000" />
<INSTANCE dmtype="mango:EpochPositionErrors" dmrole="mango:EpochPosition.errors">
<INSTANCE dmtype="mango:error.PErrorEllipse" dmrole="mango:EpochPositionErrors.position">
<ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorEllipse.semiMajorAxis" unit="mas" ref="coo_err_maja"/>
Expand Down
38 changes: 35 additions & 3 deletions pyvo/mivot/tests/test_mango_annoter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand All @@ -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",
Expand All @@ -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():
Expand Down Expand Up @@ -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():
Expand Down
35 changes: 29 additions & 6 deletions pyvo/mivot/tests/test_sky_coord_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"ref": "pmDE",
},
"obsDate": {
"dmtype": "ivoa:RealQuantity",
"dmtype": "mango:year",
"value": 1991.25,
"unit": "yr",
"ref": None,
Expand Down Expand Up @@ -100,7 +100,7 @@
"ref": "parallax",
},
"obsDate": {
"dmtype": "ivoa:RealQuantity",
"dmtype": "mango:year",
"value": 1991.25,
"unit": "yr",
"ref": None,
Expand Down Expand Up @@ -292,24 +292,47 @@ 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)
scoo = scb.build_sky_coord()
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()
38 changes: 6 additions & 32 deletions pyvo/mivot/writer/mango_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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``.
Expand Down Expand Up @@ -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:
Expand Down
Loading