pyvo
Advanced tools
| changelog: | ||
| exclude: | ||
| authors: | ||
| - dependabot | ||
| - pre-commit-ci |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| *************************************************** | ||
| MIVOT (``pyvo.mivot``): How to annotate data - Tips | ||
| *************************************************** | ||
| The annotation process is intended to be performed at the server level. | ||
| How it is implemented depends on the related DAL protocol, the framework used, | ||
| and the available metadata. | ||
| This process likely occurs before the data table is streamed out because | ||
| the Mivot block must precede the TABLE block. | ||
| This means it cannot use the table FIELDs, but rather some internal representation. | ||
| However, the examples below use the FIELDs to demonstrate how an annotation task could work. | ||
| Map a magnitude to a Mango Brightness property | ||
| ============================================== | ||
| Assuming that our dataset has the two following fields, let's map the magnitude in the J band | ||
| to the ``mango:Brightness`` class. | ||
| .. code-block:: xml | ||
| <FIELD name="Jmag" ucd="phot.mag;em.IR.J" datatype="float" width="6" precision="3" unit="mag"> | ||
| <DESCRIPTION>?(jmag) 2MASS J-band magnitude</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="e_Jmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"> | ||
| <DESCRIPTION>?(ejmag) Error on Jmag</DESCRIPTION> | ||
| </FIELD> | ||
| The MANGO brightness class packs together 3 components: the magnitude, its error and the photometric calibration. | ||
| Mivot serializations of the photometric calibrations are given by the SVO `Filter Profile Service <https://svo2.cab.inta-csic.es/svo/theory/fps/>`_. | ||
| The first thing to do is to get the FPS identifier of the searched filter (2MASS J in our case). | ||
| Once the filter is selected, the identifier of the calibration in the desired system can by copied from the | ||
| `FPS <https://svo2.cab.inta-csic.es/svo/theory/fps/index.php?id=2MASS/2MASS.J&&mode=browse&gname=2MASS&gname2=2MASS#filter>`_ | ||
| page as shown below. | ||
| .. image:: _images/filterProfileService.png | ||
| :width: 500 | ||
| :alt: FPS screen shot. | ||
| Now, we can build the mapping parameters and apply them to add the mapping of that property. | ||
| .. code-block:: python | ||
| votable = parse("SOME/VOTABLE/PATH") | ||
| builder = InstancesFromModels(votable, dmid="URAT1") | ||
| # Add the mapping of a brightness property | ||
| builder.add_mango_brightness( photcal_id="2MASS/2MASS.J/Vega", | ||
| mapping={"value": "Jmag", | ||
| "error": { "class": "PErrorSym1D", "sigma": "e_Jmag"} | ||
| }, | ||
| semantics={"description": "magnitude J", | ||
| "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#magnitude", | ||
| "label": "magnitude"}) | ||
| # Once all all properties have been mapped, we can | ||
| # tell the builder to complete the mapping block | ||
| builder.pack_into_votable() | ||
| The mapping parameters can be interpreted that way: | ||
| - The photometric calibration match the ``2MASS/2MASS.J/Vega`` FPS output | ||
| - The magnitude is given by the FIELD identified by ``Jmag`` | ||
| - The magnitude error, which is symmetrical, is given by the FIELD identified by ``e_Jmag`` | ||
| - The optional semantics block of the property (see the MANGO specification) indicates that the | ||
| property is a magnitude. | ||
| Map table data to a Mango EpochPosition property | ||
| ================================================ | ||
| The mapping of any property follow the same schema but with specific mapping parameters. | ||
| As it turns out, the EpochPosition can be very complex, with six parameters, their errors and their correlations. | ||
| If the VOTable fields are available during the annotation process, the API can extract a template of the mapping parameters. | ||
| .. code-block:: python | ||
| scs_srv = SCSService(" https://vizier.cds.unistra.fr/viz-bin/conesearch/V1.5/I/239/hip_main") | ||
| query_result = scs_srv.search( | ||
| pos=SkyCoord(ra=52.26708 * u.degree, dec=59.94027 * u.degree, frame='icrs'), | ||
| radius=0.5) | ||
| builder = InstancesFromModels(query_result.votable, dmid="URAT1") | ||
| # Get a mapping proposal based on the FIELD UCDs | ||
| parameters = builder.extract_epoch_position_parameters() | ||
| DictUtils.print_pretty_json(parameters) | ||
| The JSON below shows the detected mapping parameters as a dictionary whose structure matches that expected by the API. | ||
| .. code-block:: json | ||
| { | ||
| "frames": { | ||
| "spaceSys": { | ||
| "dmid": "_spaceframe_ICRS_BARYCENTER" | ||
| }, | ||
| "timeSys": {} | ||
| }, | ||
| "mapping": { | ||
| "longitude": "t1_c8", | ||
| "latitude": "t1_c9", | ||
| "parallax": "t1_c11", | ||
| "pmLongitude": "t1_c12", | ||
| "pmLatitude": "t1_c13", | ||
| "errors": { | ||
| "properMotion": { | ||
| "class": "PErrorSym2D", | ||
| "sigma1": "e_pmRA", | ||
| "sigma2": "e_pmDE" | ||
| } | ||
| }, | ||
| "correlations": {} | ||
| }, | ||
| "semantics": { | ||
| "description": "6 parameters position", | ||
| "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#astronomical-location", | ||
| "label": "Astronomical location" | ||
| } | ||
| } | ||
| This template can be updated manually or by any other means, and then used to adjust the "EpochPosition" mapping. | ||
| .. code-block:: python | ||
| # Add the EpochPosition to the annotations with the modified mapping parameters | ||
| builder.add_mango_epoch_position(**parameters) | ||
| builder.pack_into_votable() | ||
| ****************************************************** | ||
| MIVOT (``pyvo.mivot``): Annotation Writer - Public API | ||
| ****************************************************** | ||
| This API allows to easily map VOTable data to the Mango data model (both native and imported components). | ||
| Only a little knowledge of the models is required. | ||
| Mango is a model designed to enhance the description of table data in a way that each table | ||
| row can be interpreted as a Mango Object. | ||
| Mango objects are made of a property container, a description of the data origin and links | ||
| on other Mango objects (not implemented yet). | ||
| In this current implementation, only 3 properties are supported (Epoch position, photometry, and color) | ||
| in addition to the data origin that can be added as literal values (not connected with table data). | ||
| The pseudo codes below show the way to use this API. | ||
| The first step is to create the Annotation Builder and connect it to the VOTable to be annotated. | ||
| .. code-block:: python | ||
| votable = parse("MY/VOTABLE") | ||
| builder = InstancesFromModels(votable, dmid="DR3Name") | ||
| The ``dmid`` optional parameter gives the column (ID or name) to be used as identifier of the Mango objects. | ||
| The builder is then ready to get the properties to add to the Mango object. | ||
| .. code-block:: python | ||
| builder.add_mango_magnitude(photcal_id=photcal_id, mapping=mapping, semantics=semantics) | ||
| builder.add_mango_magnitude(photcal_id=other_photcal_id, mapping=other_mapping, semantics=other_semantics) | ||
| builder.add_mango_color(filter_ids=filter_ids, mapping=mapping, semantics=semantics) | ||
| builder.add_mango_epoch_position(frames=frames, mapping=mapping, semantics=semantics) | ||
| We can now add the description of the data origin. | ||
| .. code-block:: python | ||
| builder.add_query_origin(mapping) | ||
| - The order in which the components are added does not matter. | ||
| - The details of the parameters are described below. | ||
| Now the MIVOT block can be completed and inserted into the VOtable. | ||
| .. code-block:: python | ||
| builder.pack_into_votable() | ||
| votable.to_xml("MY/ANNOTATED/VOTABLE") | ||
| About Parameters | ||
| ================ | ||
| Mappings are always given as dictionaries, where keys are the model roles and values | ||
| are either column names or literal values. | ||
| The lists of supported roles are given in the :py:mod:`pyvo.mivot.glossary`. | ||
| The 3 functions adding properties have all 3 arguments | ||
| - ``filter/frame``: Map of the coordinate systems or photometric calibrations that apply to the property. | ||
| All values specified here are considered literal. | ||
| The corresponding Mivot instances are placed in the GLOBALS block. | ||
| - **Photometric filter**: must be given as a filter profile service identifier (filter id followed with the photometric system) | ||
| - Identifiers can be found on the SVO `page <http://svo2.cab.inta-csic.es/theory/fps/>`_ | ||
| (example: ``GAIA/GAIA3.Grp/AB``) | ||
| - The FPS service returns a full calibration instance, which is then split into a filter object | ||
| and a calibration object that refers to that filter. | ||
| - Each one of these components has its own ``dmid`` generated by the API. ``dmid`` can be used to reference them. | ||
| Example for filter ``GAIA/GAIA3.Grp/AB``: | ||
| - photometric calibration identifer: ``dmid="_photcal_GAIA_GAIA3_Grvs_AB"`` | ||
| - filter identifier ``dmid="_filter_GAIA_GAIA3_Grvs_AB"`` | ||
| - **Coordinate systems**: Can be given either by ``dmid`` or by parameters | ||
| (see `pyvo.mivot.writer.InstancesFromModels.add_simple_space_frame` | ||
| and `pyvo.mivot.writer.InstancesFromModels.add_simple_time_frame`). | ||
| - by ``dmid``: Identifiers are generated by the API when a frame is added in the GLOBALS. | ||
| (example ``{"dmid": "_spaceframe_spaceRefFrame_equinox_refPosition"}``) | ||
| - by parameters: The mapping parameters are given as dictionaries as for the mapping (see below) | ||
| (example ``{"spaceRefFrame": "ICRS", "refPosition": 'BARYCENTER'}``) | ||
| - ``Mapping``: Mapping of the table data to the property attributes. | ||
| The fine structure of these dictionaries is specific to each mapped class, | ||
| but all follow the same pattern. | ||
| Values specified as strings are considered to be column identifiers, | ||
| unless the string starts with a '*'. In this case, the stripped string is taken as the literal value. | ||
| Other value types (numeric or boolean) are all considered as literals. | ||
| +-------------+---------------------------------+ | ||
| | **value** | **attribute value** | | ||
| +=============+=================================+ | ||
| | "\*M31" | "M31" | | ||
| +-------------+---------------------------------+ | ||
| | "ObjName" | value of the column "ObjName" | | ||
| +-------------+---------------------------------+ | ||
| | True | True | | ||
| +-------------+---------------------------------+ | ||
| | 123456 | 123456 | | ||
| +-------------+---------------------------------+ | ||
| | 45.8987 | 45.8987 | | ||
| +-------------+---------------------------------+ | ||
| - ``semantics``: Semantic tags (text + vocabulary entry) that apply to the property. | ||
| +-------------+---------------------------------------------------------+ | ||
| + **key** | **value** + | ||
| +=============+=========================================================+ | ||
| + description + free text description of the property + | ||
| +-------------+---------------------------------------------------------+ | ||
| + uri + URI of the vocabulary term to which the property refers + | ||
| +-------------+---------------------------------------------------------+ | ||
| + label + vocabulary term to which the property refers + | ||
| +-------------+---------------------------------------------------------+ | ||
| All ``semantics`` fields are considered literal values. | ||
| Add Query origin | ||
| ---------------- | ||
| Add the Mango ``QueryOrigin`` instance to the current ``MangoObject``. | ||
| .. figure:: _images/mangoDataOrigin.png | ||
| :width: 500 | ||
| DataOrigin package of Mango. | ||
| ``QueryOrigin`` is the object grouping together all the components needed to model the origin | ||
| of the MangoObject. It is always identified with ``dmid="_origin"`` | ||
| .. code-block:: python | ||
| builder.add_query_origin(mapping) | ||
| The detail of the ``mapping`` parameter is given in the `pyvo.mivot.writer.InstancesFromModels.add_query_origin` documentation | ||
| The ``QueryOrigin`` object can be automatically built from the INFO tags of the VOtable. The success of this operation depends | ||
| on the way INFO tags are populated. | ||
| The method below, analyzes the INFO tags and insert the resulting query origin into the annotations. | ||
| .. code-block:: python | ||
| builder.extract_data_origin() | ||
| - This code has been optimized to work with Vizier output. | ||
| - INFO tags of the VOTable header are analysed to set the ``QueryOrigin`` attributes. | ||
| - INFO tags of the header of the first resource are analyzed to set the ``DataOrigin`` objects. | ||
| - The automatic mapping does not work for VOtable joining several tables yet. | ||
| Add Properties | ||
| -------------- | ||
| The main purpose of the ``MangoObject`` is to collect various properties contained in the data row, | ||
| although synthetic properties (literal value only) can be added as well. | ||
| - The properties are stored in a container named ``propertyDock``. | ||
| - During he annotation process, properties are added one by one by specific methods. | ||
| .. figure:: _images/mangoProperties.png | ||
| :width: 500 | ||
| Properties supported by Mango. | ||
| Add EpochPosition | ||
| ^^^^^^^^^^^^^^^^^ | ||
| The ``EpochPosition`` property describes the astrometry of a moving source. | ||
| .. figure:: _images/mangoEpochPosition.png | ||
| :width: 500 | ||
| EpochPosition components of Mango. | ||
| It handles six parameters (position, proper motion, parallax and radial velocity) valid at a given epoch | ||
| (``obsDate`` field) with their correlations and errors and the coordinate system for both space and time axis. | ||
| .. code-block:: python | ||
| builder.add_epoch_position(frames, mapping, semantics) | ||
| The detail of the parameters is given with the description of the | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_mango_epoch_position` method. | ||
| The first parameter (``frames``) specifies both space and time frames. | ||
| It can either contain the frame dmid-s if they are already installed, for instance from TIMESYS and COOSYS tags, | ||
| or the mapping elements needed to install them: | ||
| Both frames can be automatically extracted from the COOSYS and TIMSYS VOTable elements. | ||
| .. code-block:: python | ||
| frame_mapping = builder.extract_frames() | ||
| builder.add_epoch_position(frame_mapping, mapping, semantics) | ||
| This automatic metedata extraction can be extended to any method parameters. | ||
| - COOSYS -> coords:SpaceSys | ||
| - TIMESYS -> coords:TimeSys | ||
| - FIELD -> mango:EpochPosition | ||
| .. code-block:: python | ||
| epoch_position_mapping = builder.extract_epoch_position_parameters() | ||
| builder.add_mango_epoch_position(**epoch_position_mapping) | ||
| However, it is advisable to take a look at the automatic mapping, as its content | ||
| is highly dependent on the VO table metadata, and the risk of incompleteness, | ||
| mismatches or confusion cannot be ruled out. | ||
| Add Brightness | ||
| ^^^^^^^^^^^^^^ | ||
| The ``Brightness`` binds a flux or a magnitude with an error and a photometric calibration. | ||
| .. code-block:: python | ||
| builder.add_mango_brightness(photcal_id, mapping, semantics) | ||
| The detail of the parameters is given with the | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_mango_brightness` docstring. | ||
| Add Color | ||
| ^^^^^^^^^ | ||
| The ``Color`` binds to a Color index or an hardness ratio value with an error and two photometric filters. | ||
| .. code-block:: python | ||
| builder.add_mango_color(filter_ids, mapping, semantics) | ||
| The detail of the parameters is given with the | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_mango_color` docstring. | ||
| Reference/API | ||
| ============= | ||
| .. automodapi:: pyvo.mivot.writer | ||
| .. automodapi:: pyvo.mivot.utils | ||
| .. automodapi:: pyvo.mivot.glossary |
| ************************************************************ | ||
| MIVOT (``pyvo.mivot``): How to use annotated data - Examples | ||
| ************************************************************ | ||
| Photometric properties readout | ||
| ============================== | ||
| This example is based on VOTables provided by the ``XTapDB`` service. | ||
| This service exposes the slim `4XMM dr14 catalogue <http://xmmssc.irap.omp.eu/>`_. | ||
| It is able to map query responses on the fly to the MANGO data model. | ||
| The annotation process only annotates the columns that are selected by the query. | ||
| The following properties are supported: | ||
| - ``mango:Brightness`` to which fluxes are mapped | ||
| - ``mango:Color`` to which hardness ratio are mapped | ||
| - ``mango:EpochPosition`` to which positions and first observation dates are mapped | ||
| - ``mango:Status`` to which quality flags of the source detections are mapped | ||
| A specific response format (``application/x-votable+xml;content=mivot``) must be set in order | ||
| to tell the server to annotate the queried data. | ||
| (*Please read the comment inside the code snippet carefully to fully understand the process*) | ||
| .. code-block:: python | ||
| import pytest | ||
| from pyvo.utils import activate_features | ||
| from pyvo.dal import TAPService | ||
| from pyvo.mivot.utils.xml_utils import XmlUtils | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| from pyvo.mivot.viewer.mivot_viewer import MivotViewer | ||
| # Enable MIVOT-specific features in the pyvo library | ||
| activate_features("MIVOT") | ||
| service = TAPService('https://xcatdb.unistra.fr/xtapdb') | ||
| result = service.run_sync( | ||
| """ | ||
| SELECT TOP 5 * FROM "public".mergedentry | ||
| """, | ||
| format="application/x-votable+xml;content=mivot" | ||
| ) | ||
| # The MIVOT viewer generates the model view of the data | ||
| m_viewer = MivotViewer(result, resolve_ref=True) | ||
| # Print out the Mivot annotations read out of the VOtable | ||
| # This statement is just for a pedagogic purpose (access to a private attribute) | ||
| XmlUtils.pretty_print(m_viewer._mapping_block) | ||
| In this first step we just queried the service and we built the object that will process the Mivot annotations. | ||
| The Mivot block printing output is too long to be listed here. However, the screenshot below shows its shallow structure. | ||
| .. image:: _images/xtapdbXML.png | ||
| :width: 500 | ||
| :alt: Shallow structure of the annotation block. | ||
| - The GLOBALS section contains all the coordinate systems (in a wide sense). This includes the allowed values for | ||
| the detection flags and the photometric calibrations. | ||
| - The TEMPLATES section contains the objects to which table data is mapped. In this example, there is one | ||
| ``MangoObject`` instance which holds all the mapped properties. | ||
| At instantiation time, the viewer reads the first data row, which must exist, | ||
| in order to construct a Python object that reflects the mapped model. | ||
| .. code-block:: python | ||
| # Build a Python object matching the TEMPLATES content and | ||
| # which leaves are set with the values of the first row | ||
| mango_object = m_viewer.dm_instance | ||
| # Print out the content of the Python object | ||
| # This statement is just for a pedagogic purpose | ||
| DictUtils.print_pretty_json(mango_object.to_dict()) | ||
| The annotations are consumed by this dynamic Python object which leaves are set with the data of the current row. | ||
| You can explore the structure of this object by using the printed dictionary or standard object paths as shown below. | ||
| Now, we can iterate through the table data and retrieve an updated Mivot instance for each row. | ||
| .. code-block:: python | ||
| while m_viewer.next_row_view(): | ||
| if mango_object.dmtype == "mango:MangoObject": | ||
| print(f"Read source {mango_object.identifier.value} {mango_object.dmtype}") | ||
| for mango_property in mango_object.propertyDock: | ||
| if mango_property.dmtype == "mango:Brightness": | ||
| if mango_property.value.value: | ||
| mag_value = mango_property.value.value | ||
| mag_error = mango_property.error.sigma.value | ||
| phot_cal = mango_property.photCal | ||
| spectral_location = phot_cal.photometryFilter.spectralLocation | ||
| mag_filter = phot_cal.identifier.value | ||
| spectral_location = phot_cal.photometryFilter.spectralLocation | ||
| mag_wl = spectral_location.value.value | ||
| sunit = spectral_location.unitexpression.value | ||
| print(f" flux at {mag_wl} {sunit} (filter {mag_filter}) is {mag_value:.2e} +/- {mag_error:.2e}") | ||
| Read source 4XMM J054329.3-682106 mango:MangoObject | ||
| flux at 0.35 keV (filter XMM/EPIC/EB1) is 8.35e-14 +/- 3.15e-14 | ||
| flux at 0.75 keV (filter XMM/EPIC/EB2) is 3.26e-15 +/- 5.45e-15 | ||
| flux at 6.1 keV (filter XMM/EPIC/EB8) is 8.68e-14 +/- 6.64e-14 | ||
| ... | ||
| ... | ||
| The same code can easily be connected with matplotlib to plot SEDs as shown below (code not provided). | ||
| .. image:: _images/xtapdbSED.png | ||
| :width: 500 | ||
| :alt: XMM SED | ||
| It is to noted that the current table row keeps available through the Mivot viewer. | ||
| .. code-block:: python | ||
| row = m_viewer.table_row | ||
| .. important:: | ||
| The code shown in this example can be used with any VOTable that has data mapped to MANGO. | ||
| It contains no features specific to the XtatDB output. | ||
| This is exactly the purpose of the MIVOT/MANGO abstraction layer: to allow the same processing | ||
| to be applied to any annotated VOTable. | ||
| The same client code can be reused in many places with many datasets, provided they are annotated. | ||
| EpochPosition property readout | ||
| ============================== | ||
| This example is based on a VOtable resulting on a Vizier cone search. | ||
| This service maps the data to the ``EpochPosition`` MANGO property, | ||
| which models a full source's astrometry at a given date. | ||
| .. warning:: | ||
| At the time of writing, Vizier only mapped positions and proper motions (when available), | ||
| and the definitive epoch class had not been adopted. | ||
| Therefore, this implementation may differ a little bit from the standard model. | ||
| Vizier does not wrap the source properties in a MANGO object, | ||
| but rather lists them in the Mivot *TEMPLATES*. | ||
| The annotation reader must support both designs. | ||
| In the first step below, we run a standard cone search query by using the standard PyVO API. | ||
| .. code-block:: python | ||
| import pytest | ||
| import astropy.units as u | ||
| from astropy.coordinates import SkyCoord | ||
| from pyvo.dal.scs import SCSService | ||
| from pyvo.utils import activate_features | ||
| from pyvo.mivot.viewer.mivot_viewer import MivotViewer | ||
| from pyvo.mivot.features.sky_coord_builder import SkyCoordBuilder | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| # Enable MIVOT-specific features in the pyvo library | ||
| activate_features("MIVOT") | ||
| scs_srv = SCSService("https://vizier.cds.unistra.fr/viz-bin/conesearch/V1.5/I/239/hip_main") | ||
| query_result = scs_srv.search( | ||
| pos=SkyCoord(ra=52.26708 * u.degree, dec=59.94027 * u.degree, frame='icrs'), | ||
| radius=0.5) | ||
| # The MIVOt viewer generates the model view of the data | ||
| m_viewer = MivotViewer(query_result, resolve_ref=True) | ||
| Once the query is finished, we can get a reference to the object that will process the Mivot annotations. | ||
| .. code-block:: python | ||
| # Build a Python object matching the TEMPLATES content and | ||
| # which leaves are set with the values of the first row | ||
| mango_property = m_viewer.dm_instance | ||
| # Print out the content of the Python object | ||
| # This statement is just for a pedagogic purpose | ||
| DictUtils.print_pretty_json(mango_property.to_dict()) | ||
| The annotations are consumed by this dynamic Python object which leaves are set with the data of the current row. | ||
| You can explore the structure of this object by using standard object paths or by browsing the dictionary shown below. | ||
| .. code-block:: json | ||
| { | ||
| "dmtype": "mango:EpochPosition", | ||
| "longitude": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
| "value": 51.64272638, | ||
| "unit": "deg" | ||
| }, | ||
| "latitude": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
| "value": 60.28156089, | ||
| "unit": "deg" | ||
| }, | ||
| "pmLongitude": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
| "value": 13.31, | ||
| "unit": "mas/yr" | ||
| }, | ||
| "pmLatitude": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
| "value": -23.43, | ||
| "unit": "mas/yr" | ||
| }, | ||
| "epoch": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
| "value": 1991.25, | ||
| "unit": "yr" | ||
| }, | ||
| "parallax": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
| "value": 5.12, | ||
| "unit": "mas" | ||
| }, | ||
| "spaceSys": { | ||
| "dmtype": "coords:SpaceSys", | ||
| "dmid": "SpaceFrame_ICRS", | ||
| "dmrole": "mango:EpochPosition.spaceSys", | ||
| "frame": { | ||
| "dmrole": "coords:PhysicalCoordSys.frame", | ||
| "dmtype": "coords:SpaceFrame", | ||
| "spaceRefFrame": { | ||
| "dmtype": "ivoa:string", | ||
| "value": "ICRS" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| The reader can transform ``EpochPosition`` instances into ``SkyCoord`` instances. | ||
| These can then be used for further scientific processing. | ||
| .. code-block:: python | ||
| while m_viewer.next_row_view(): | ||
| if mango_property.dmtype == "mango:EpochPosition": | ||
| scb = SkyCoordBuilder(mango_property.to_dict()) | ||
| # do whatever process with the SkyCoord object | ||
| print(scb.build_sky_coord()) | ||
| .. important:: | ||
| Similar to the previous example, this code can be used with any VOTable with data mapped to MANGO. | ||
| It contains no features specific to the Vizier output. | ||
| It avoids the need for users to build SkyCoord objects by hand from VOTable fields, | ||
| which is never an easy task. | ||
| The next section provides some tips to use the API documented in the annoter `page <annoter.html>`_. |
| ****************************************************** | ||
| MIVOT (``pyvo.mivot``): Annotation Viewer - Public API | ||
| ****************************************************** | ||
| Introduction | ||
| ============ | ||
| .. pull-quote:: | ||
| Model Instances in VOTables (MIVOT) defines a syntax to map VOTable | ||
| data to any model serialized in VO-DML. The annotation operates as a | ||
| bridge between the data and the model. It associates the column/param | ||
| metadata from the VOTable to the data model elements (class, attributes, | ||
| types, etc.) [...]. | ||
| The data model elements are grouped in an independent annotation block | ||
| complying with the MIVOT XML syntax. This annotation block is added | ||
| as an extra resource element at the top of the VOTable result resource. The | ||
| MIVOT syntax allows to describe a data structure as a hierarchy of classes. | ||
| It is also able to represent relations and composition between them. It can | ||
| also build up data model objects by aggregating instances from different | ||
| tables of the VOTable (get more in :doc:`index`). | ||
| Using the API | ||
| ============= | ||
| Integrated Readout | ||
| ------------------ | ||
| The ``ModelViewer`` module manages access to data mapped to a model through dynamically | ||
| generated objects (``MivotInstance`` class). | ||
| The example below shows how a VOTable result of a cone-search query can be parsed and data | ||
| mapped to the ``EpochPosition`` class. | ||
| .. doctest-remote-data:: | ||
| >>> import astropy.units as u | ||
| >>> from astropy.coordinates import SkyCoord | ||
| >>> from pyvo.dal.scs import SCSService | ||
| >>> from pyvo.utils.prototype import activate_features | ||
| >>> from pyvo.mivot.version_checker import check_astropy_version | ||
| >>> from pyvo.mivot.viewer.mivot_viewer import MivotViewer | ||
| >>> activate_features("MIVOT") | ||
| >>> if check_astropy_version() is False: | ||
| ... pytest.skip("MIVOT test skipped because of the astropy version.") | ||
| >>> scs_srv = SCSService("https://vizier.cds.unistra.fr/viz-bin/conesearch/V1.5/I/239/hip_main") | ||
| >>> m_viewer = MivotViewer( | ||
| ... scs_srv.search( | ||
| ... pos=SkyCoord(ra=52.26708 * u.degree, dec=59.94027 * u.degree, frame='icrs'), | ||
| ... radius=0.05 | ||
| ... ), | ||
| ... resolve_ref=True | ||
| ... ) | ||
| >>> mivot_instance = m_viewer.dm_instance | ||
| >>> print(mivot_instance.dmtype) | ||
| mango:EpochPosition | ||
| >>> print(mivot_instance.spaceSys.frame.spaceRefFrame.value) | ||
| ICRS | ||
| >>> while m_viewer.next_row_view(): | ||
| ... print(f"position: {mivot_instance.latitude.value} {mivot_instance.longitude.value}") | ||
| position: 59.94033461 52.26722684 | ||
| In this example, the data readout is totally managed by the ``MivotViewer`` instance. | ||
| The ``astropy.io.votable`` API is encapsulated in this module. | ||
| Model leaves (class attributes) are complex types that provide additional information: | ||
| - ``value``: attribute value | ||
| - ``dmtype``: attribute type such as defined in the Mivot annotations | ||
| - ``unit``: attribute unit such as defined in the Mivot annotations | ||
| - ``ref``: identifier of the table column mapped on the attribute | ||
| The model view on a data row can also be passed as a Python dictionary | ||
| using the ``dict`` property of ``MivotInstance``. | ||
| .. code-block:: python | ||
| :caption: Working with a model view as a dictionary | ||
| (the JSON layout has been squashed for display purpose) | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| mivot_instance = m_viewer.dm_instance | ||
| mivot_object_dict = mivot_object.dict | ||
| DictUtils.print_pretty_json(mivot_object_dict) | ||
| { | ||
| "dmtype": "EpochPosition", | ||
| "longitude": {"value": 359.94372764, "unit": "deg"}, | ||
| "latitude": {"value": -0.28005255, "unit": "deg"}, | ||
| "pmLongitude": {"value": -5.14, "unit": "mas/yr"}, | ||
| "pmLatitude": {"value": -25.43, "unit": "mas/yr"}, | ||
| "epoch": {"value": 1991.25, "unit": "year"}, | ||
| "Coordinate_coordSys": { | ||
| "dmtype": "SpaceSys", | ||
| "dmid": "SpaceFrame_ICRS", | ||
| "dmrole": "coordSys", | ||
| "spaceRefFrame": {"value": "ICRS"}, | ||
| }, | ||
| } | ||
| - It is recommended to use a copy of the | ||
| dictionary as it will be rebuilt each time the ``dict`` property is invoked. | ||
| - The default representation of ``MivotInstance`` instances is made with a pretty | ||
| string serialization of this dictionary. | ||
| Per-Row Readout | ||
| --------------- | ||
| The annotation schema can also be applied to table rows read outside of the ``MivotViewer`` | ||
| with the `astropy.io.votable` API: | ||
| .. code-block:: python | ||
| :caption: Accessing the model view of Astropy table rows | ||
| votable = parse(path_to_votable) | ||
| table = votable.resources[0].tables[0] | ||
| # init the viewer | ||
| mivot_viewer = MivotViewer(votable, resource_number=0) | ||
| mivot_object = mivot_viewer.dm_instance | ||
| # and feed it with the table row | ||
| read = [] | ||
| for rec in table.array: | ||
| mivot_object.update(rec) | ||
| read.append(mivot_object.longitude.value) | ||
| # show that the model retrieve the correct data values | ||
| assert rec["RAICRS"] == mivot_object.longitude.value | ||
| assert rec["DEICRS"] == mivot_object.latitude.value | ||
| In this case, it is up to the user to ensure that the read data rows are those mapped by the Mivot annotations. | ||
| For XML Hackers | ||
| --------------- | ||
| The model instances can also be serialized as XML elements that can be parsed with XPath queries. | ||
| .. code-block:: python | ||
| :caption: Accessing the XML view of the mapped model instances | ||
| with MivotViewer(path_to_votable) as mivot_viewer: | ||
| while mivot_viewer.next_row_view(): | ||
| xml_view = mivot_viewer.xml_view | ||
| # do whatever you want with this XML element | ||
| It is to be noted that ``mivot_viewer.xml_view`` is a shortcut | ||
| for ``mivot_viewer.xml_view.view`` where ``mivot_viewer.xml_view`` | ||
| is is an instance of ``pyvo.mivot.viewer.XmlViewer``. | ||
| This object provides many functions facilitating the XML parsing. | ||
| Class Generation in a Nutshell | ||
| ------------------------------ | ||
| MIVOT reconstructs model structures with 3 elements: | ||
| - ``INSTANCE`` for the objects | ||
| - ``ATTRIBUTE`` for the attributes | ||
| - ``COLLECTION`` for the elements with a cardinality greater than 1 | ||
| The role played by each of these elements in the model hierarchy is defined | ||
| by its ``@dmrole`` XML attribute. Types of both ``INSTANCE`` and ``ATTRIBUTE`` are defined by | ||
| their ``@dmtype`` XML attributes. | ||
| ``MivotInstance`` classes are built by following MIVOT annotation structure: | ||
| - ``INSTANCE`` are represented by Python classes | ||
| - ``ATTRIBUTE`` are represented by Python class fields | ||
| - ``COLLECTION`` are represented by Python lists ([]) | ||
| ``@dmrole`` and ``@dmtype`` cannot be used as Python keywords as such, because they are built from VO-DML | ||
| identifiers, which have the following structure: ``model:a.b``. | ||
| - Only the last part of the path is kept for attribute names. | ||
| - For class names, forbidden characters (``:`` or ``.``) are replaced with ``_``. | ||
| - Original ``@dmtype`` are kept as attributes of generated Python objects. | ||
| - The structure of the ``MivotInstance`` objects can be inferred from the mapped model in 2 different ways: | ||
| - 1. From the MIVOT instance property ``MivotInstance.dict`` a shown above. | ||
| This is a pure Python dictionary but its access can be slow because it is generated | ||
| on the fly each time the property is invoked. | ||
| - 2. From the internal class dictionary ``MivotInstance.__dict__`` | ||
| (see the Python `data model <https://docs.python.org/3/reference/datamodel.html>`_). | ||
| .. code-block:: python | ||
| :caption: Exploring the MivotInstance structure with the internal dictionaries | ||
| mivot_instance = mivot_viewer.dm_instance | ||
| print(mivot_instance.__dict__.keys()) | ||
| dict_keys(['dmtype', 'longitude', 'latitude', 'pmLongitude', 'pmLatitude', 'epoch', 'Coordinate_coordSys']) | ||
| print(mivot_instance.Coordinate_coordSys.__dict__.keys()) | ||
| dict_keys(['dmtype', 'dmid', 'dmrole', 'spaceRefFrame']) | ||
| print(mivot_instance.Coordinate_coordSys.spaceRefFrame.__dict__.keys()) | ||
| dict_keys(['dmtype', 'value', 'unit', 'ref']) | ||
| Reference/API | ||
| ============= | ||
| .. automodapi:: pyvo.mivot.viewer |
| *************************************************** | ||
| MIVOT (``pyvo.mivot``): Annotation Writer - Dev API | ||
| *************************************************** | ||
| Introduction | ||
| ============ | ||
| .. pull-quote:: | ||
| Model Instances in VOTables (MIVOT) defines a syntax to map VOTable | ||
| data to any model serialized in VO-DML. The annotation operates as a | ||
| bridge between the data and the model. It associates the column/param | ||
| metadata from the VOTable to the data model elements (class, attributes, | ||
| types, etc.) [...]. | ||
| The data model elements are grouped in an independent annotation block | ||
| complying with the MIVOT XML syntax. This annotation block is added | ||
| as an extra resource element at the top of the VOTable result resource. The | ||
| MIVOT syntax allows to describe a data structure as a hierarchy of classes. | ||
| It is also able to represent relations and composition between them. It can | ||
| also build up data model objects by aggregating instances from different | ||
| tables of the VOTable (get more in :doc:`index`). | ||
| - Model Instances in VOTables is a VO `standard <https://ivoa.net/documents/MIVOT/20230620/REC-mivot-1.0.pdf>`_ | ||
| - Requires Astropy>=6.0 | ||
| - ``pyvo.mivot`` is a prototype feature which must be activated with ``activate_features("MIVOT")`` | ||
| Use the API | ||
| =========== | ||
| Build Annotation Object per Object | ||
| ---------------------------------- | ||
| This documentation is intended for developers of data model classes who want to map them to VOTables | ||
| and not for end users. A future version will allow end users to create annotations with | ||
| ready-to-use data model building blocks. | ||
| Creating annotations consists of 3 steps: | ||
| #. Create individual instances (INSTANCE) using the ``MivotInstance`` class: objects are | ||
| built attribute by attribute. These components can then be aggregated into | ||
| more complex objects following the structure of the mapped model(s). | ||
| #. Wrap the annotations with the ``MivotAnnotations`` class: declare to the annotation builder | ||
| the models used, and place individual instances at the right place (TEMPLATES or GLOBALS). | ||
| #. Insert the annotations into a VOtable by using the Astropy API (wrapped in the package logic). | ||
| The annotation builder does not check whether the XML conforms to any particular model. | ||
| It simply validates it against the MIVOT XML Schema if the ``xmlvalidator`` package if is installed. | ||
| The example below shows a step-by-step construction of a MIVOT block mapping | ||
| a position with its error (as defined in the ``MANGO`` draft) | ||
| and its space coordinate system (as defined in the ``Coordinates`` model and imported by ``MANGO``). | ||
| Build the empty MIVOT Block | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| - The MIVOT block consists of: | ||
| - A process status | ||
| - A list of mapped models | ||
| - A list of globals, which are objects not associated with | ||
| VOTable data and that can be shared by any other MIVOT instance. | ||
| - A list of templates, which are objects that are connected to | ||
| VOTable data and whose leaf values change from one row to another. | ||
| - ``MIVOT`` is still an experimental feature which must be activated | ||
| .. code-block:: python | ||
| from astropy.io.votable import parse | ||
| from pyvo.utils import activate_features | ||
| from pyvo.mivot.utils.exceptions import MappingException | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| from pyvo.mivot.writer.annotations import MivotAnnotations | ||
| from pyvo.mivot.writer.instance import MivotInstance | ||
| from pyvo.mivot.viewer.mivot_viewer import MivotViewer | ||
| activate_features("MIVOT") | ||
| mivot_annotations = MivotAnnotations() | ||
| mivot_annotations.add_model( | ||
| "ivoa", "https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml" | ||
| ) | ||
| mivot_annotations.add_model( | ||
| "coords", "https://www.ivoa.net/xml/STC/20200908/Coords-v1.0.vo-dml.xml" | ||
| ) | ||
| mivot_annotations.add_model( | ||
| "mango", | ||
| "https://raw.githubusercontent.com/lmichel/MANGO/draft-0.1/vo-dml/mango.vo-dml.xml", | ||
| ) | ||
| mivot_annotations.set_report(True, "PyVO Tuto") | ||
| Build the Coordinate System Object | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| The space coordinate system is made of a space frame and a reference position, both wrapped in a ``coords:SpaceSys`` | ||
| object (see the `Coordinates <https://ivoa.net/documents/Coords/20221004/index.html>`_ data model). | ||
| The time coordinate system is made of a time frame and a reference position, both wrapped in a ``coords:TimeSys`` | ||
| object. | ||
| - Each of these objects have a ``dmid`` which will be used as a reference by the ``EpochPosition`` instance. | ||
| .. code-block:: python | ||
| mivot_annotations.add_simple_space_frame(ref_frame="FK5", | ||
| ref_position="BARYCENTER", | ||
| equinox="J2000", | ||
| dmid="_spacesys" | ||
| ) | ||
| mivot_annotations.add_simple_time_frame(ref_frame="TCB", | ||
| ref_position="BARYCENTER", | ||
| dmid="_timesys" | ||
| ) | ||
| Build the EpochPosition Object | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| - In this example we only use the position attributes (RA/DEC) of the ``EpochPosition`` class. | ||
| - The reference to the space coordinate system is added at the end. | ||
| - The ``ref`` XML attributes reference columns that must be used to set the model attributes. | ||
| Their values depend on the VOTable to be mapped. | ||
| .. code-block:: python | ||
| from astropy.io.votable import parse | ||
| from pyvo.utils import activate_features | ||
| from pyvo.mivot.utils.exceptions import MappingException | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| from pyvo.mivot.writer.annotations import MivotAnnotations | ||
| from pyvo.mivot.writer.instance import MivotInstance | ||
| from pyvo.mivot.viewer.mivot_viewer import MivotViewer | ||
| activate_features("MIVOT") | ||
| position = MivotInstance(dmtype="mango:EpochPosition") | ||
| position.add_attribute( | ||
| dmtype="ivoa:RealQuantity", | ||
| dmrole="mango:EpochPosition.longitude", | ||
| unit="deg", | ||
| ref="RAICRS", | ||
| ) | ||
| position.add_attribute( | ||
| dmtype="ivoa:RealQuantity", | ||
| dmrole="mango:EpochPosition.latitude", | ||
| unit="deg", | ||
| ref="DEICRS", | ||
| ) | ||
| position.add_reference( | ||
| dmref="_spacesys", dmrole="mango:EpochPosition.spaceSys" | ||
| ) | ||
| Build the Position Error | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| - We assume that the position error is the same on both axes without correlation. | ||
| In terms of MANGO error, this corresponds to a 2x2 diagonal error matrix with two equal coefficients. | ||
| - Finally, the error is added as a component of the ``EpochPosition`` instance. | ||
| .. code-block:: python | ||
| epoch_position_error = MivotInstance( | ||
| dmtype="mango:EpochPositionErrors", dmrole="mango:EpochPosition.errors" | ||
| ) | ||
| position_error = MivotInstance( | ||
| dmtype="mango:error.ErrorCorrMatrix", | ||
| dmrole="mango:EpochPositionErrors.position", | ||
| ) | ||
| position_error.add_attribute( | ||
| dmtype="ivoa:RealQuantity", | ||
| dmrole="mango:error.ErrorCorrMatrix.sigma1", | ||
| unit="arcsec", | ||
| ref="sigm", | ||
| ) | ||
| position_error.add_attribute( | ||
| dmtype="ivoa:RealQuantity", | ||
| dmrole="mango:error.ErrorCorrMatrix.sigma2", | ||
| unit="arcsec", | ||
| ref="sigm", | ||
| ) | ||
| epoch_position_error.add_instance(position_error) | ||
| position.add_instance(epoch_position_error) | ||
| Pack the MIVOT Block | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
| - Pack the model instances previously built. | ||
| - The latest step (build_mivot_block) includes a validation of the MIVOT syntax that works only | ||
| if the ``xmlvalidator`` package has been installed. | ||
| .. code-block:: python | ||
| mivot_annotations.add_templates(position) | ||
| mivot_annotations.build_mivot_block() | ||
| Insert the MIVOT Block in a VOTable | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| - This straightforward step is based on the Astropy VOTable API. | ||
| - Annotations are stored in-memory (in the parsed VOtable). | ||
| - The mapping can be tested with the ``MivotViewer`` API (see the :doc:`viewer`) | ||
| - The VOtable must be explicitly saved on disk if needed. | ||
| .. code-block:: python | ||
| from astropy.io.votable import parse | ||
| votable = parse(votable_path) | ||
| mivot_annotations.insert_into_votable(votable) | ||
| mivot_viewer = MivotViewer(votable) | ||
| mapped_instance = mivot_viewer.dm_instance | ||
| votable.to_xml("pyvo-tuto.xml") | ||
| Validate the annotations against the models | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| - This action requires the ``mivot-validatorXXX`` package to be installed. | ||
| - It validates the mapped classes against the models they come from. | ||
| .. code-block:: shell | ||
| % pip install mivot-validator | ||
| % mivot-instance-validate pyvo-tuto.xml | ||
| ... | ||
| Valid if no error message | ||
| ... | ||
| """ | ||
| Glossary for the MIVOT package | ||
| - Model related words (hard-coded for now) | ||
| - URLs | ||
| """ | ||
| __all__ = ["Url", "IvoaType", "Roles", "CoordSystems", "ModelPrefix", | ||
| "VodmlUrl", "EpochPositionAutoMapping"] | ||
| class Url: | ||
| """ | ||
| Service URL(s) that are used by the API | ||
| """ | ||
| #: Filter Profile Service URL (SVO) | ||
| FPS = ( | ||
| "http://svo2.cab.inta-csic.es/svo/theory/fps/fpsmivot.php?PhotCalID=" | ||
| ) | ||
| class IvoaType: | ||
| """ | ||
| Primitive VODML types | ||
| """ | ||
| #: primitive type for strings | ||
| string = "ivoa:string" | ||
| #: primitive type for reals | ||
| real = "ivoa:real" | ||
| #: primitive type for real quantity (real + unit) | ||
| RealQuantity = "ivoa:RealQuantity" | ||
| #: primitive type for booleans | ||
| bool = "ivoa:boolean" | ||
| #: primitive type for a point in time | ||
| datetime = "ivoa:datatime" | ||
| class Roles: | ||
| """ | ||
| Accepted roles for all implemented classes; | ||
| correspond to the last path element of the ``dmroles`` | ||
| as defined in VODML (VODML-ID) | ||
| """ | ||
| #: Roles of the EpochPosition class that are supported | ||
| EpochPosition = [ | ||
| "longitude", | ||
| "latitude", | ||
| "parallax", | ||
| "radialVelocity", | ||
| "pmLongitude", | ||
| "pmLatitude", | ||
| "obsDate", | ||
| ] | ||
| #: Roles of the EpochPositionCorrelations class that are supported | ||
| EpochPositionCorrelations = [ | ||
| "longitudeParallax", | ||
| "latitudeParallax", | ||
| "pmLongitudeParallax", | ||
| "pmLatitudeParallax", | ||
| "longitudeLatitude", | ||
| "pmLongitudePmLatitude", | ||
| "latitudePmLatitude", | ||
| "latitudePmLongitude", | ||
| "longitudePmLatitude", | ||
| "longitudePmLongitude", | ||
| "isCovariance", | ||
| ] | ||
| #: Roles of the EpochPositionErrors class that are supported | ||
| EpochPositionErrors = [ | ||
| "parallax", | ||
| "radialVelocity", | ||
| "position", | ||
| "properMotion", | ||
| ] | ||
| #: Roles of the PErrorSym1D class that is supported | ||
| PErrorSym1D = [ | ||
| "sigma" | ||
| ] | ||
| #: Roles of the PErrorAsym1D class that are supported | ||
| PErrorAsym1D = [ | ||
| "low", | ||
| "high" | ||
| ] | ||
| #: Roles of the PErrorSym2D class that are supported | ||
| PErrorSym2D = [ | ||
| "sigma1", | ||
| "sigma2" | ||
| ] | ||
| #: Roles of the PErrorSym2D class that are supported | ||
| PErrorEllipse = [ | ||
| "semiMajorAxis", | ||
| "semiMinorAxis", | ||
| "angle" | ||
| ] | ||
| #: Roles of the PhotometricProperty class that are supported | ||
| PhotometricProperty = ["value", | ||
| "error" | ||
| ] | ||
| #: Roles of the Color class that are supported | ||
| Color = ["value", | ||
| "error", | ||
| "definition" | ||
| ] | ||
| #: Roles of the QueryOrigin class that are supported | ||
| QueryOrigin = ["publisher", "server_software", "service_protocol", | ||
| "request", "request_date", "query", "contact", "ivoid" | ||
| ] | ||
| #: Roles of the DataOrigin class that are supported | ||
| DataOrigin = ["ivoid", "reference_url", "resource_version", "creators", | ||
| "cites", "is_derived_from", "original_date", "rights", "rights_uri", "articles" | ||
| ] | ||
| #: Roles of the Article class that are supported | ||
| Article = ["identifier", "editor" | ||
| ] | ||
| class CoordSystems: | ||
| """ | ||
| Supported values for the coordinate system parameters (space and time) | ||
| """ | ||
| #: see IVOA `refframe <https://www.ivoa.net/rdf/refframe/2022-02-22/refframe.html>`_ vocabulary | ||
| space_frames = ["eq_FK4", "FK4", "eq_FK5", "FK5", "ICRS", "GALACTIC", "SUPER_GALACTIC", "ECLIPTIC"] | ||
| #: see IVOA `refposition <https://www.ivoa.net/rdf/refposition/2019-03-15/refposition.html>`_ vocabulary | ||
| ref_positions = ["BARYCENTER", "GEOCENTER", "TOPOCENTER"] | ||
| #: see IVOA `timescale <https://www.ivoa.net/rdf/timescale/2019-03-15/timescale.html>`_ vocabulary | ||
| time_frames = ["TAI", "TT", "TDT", "ET", "IAT", "UT1", | ||
| "UTC", "GMT", "GPS", "TCG", "TCB", "TBD", "LOCAL"] | ||
| #: supported time formats (could be replaced witha vocabulary later on) | ||
| time_formats = ["byear", "cxcsec", "decimalyear", "fits", | ||
| "gps", "iso", "timestamp", "jyear", "year", "jd", "mjd"] | ||
| class ModelPrefix: | ||
| """ | ||
| Model names as defined in VODML | ||
| """ | ||
| #: `VODML <https://www.ivoa.net/documents/VODML/20180910/index.html>`_ primitive types | ||
| ivoa = "ivoa" | ||
| #: VODML prefix of the MANGO model | ||
| mango = "mango" | ||
| #: VODML prefix of the `Photometry Data Model | ||
| #: <https://www.ivoa.net/documents/PHOTDM/20221101/index.html>`_ | ||
| Phot = "Phot" | ||
| #: VODML prefix of the Astronomical `Astronomical Coordinates and Coordinate Systems | ||
| #: <https://www.ivoa.net/documents/Coords/20221004/index.html>`_ datamodel | ||
| coords = "coords" | ||
| #: VODML prefix of the `Astronomical Measurements Model | ||
| #: <https://www.ivoa.net/documents/Meas/20221004/index.html>`_ | ||
| meas = "meas" | ||
| class VodmlUrl: | ||
| """ | ||
| VODML URLs of the supported models. | ||
| Names of the class attributes match the `ModelPrefix` fields. | ||
| """ | ||
| #: VODML URL of the `VODML | ||
| #: <https://www.ivoa.net/documents/VODML/20180910/index.html>`_ primitive types | ||
| ivoa = "https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml" | ||
| #: VODML URL of the MANGO model | ||
| mango = "https://raw.githubusercontent.com/ivoa-std/MANGO/refs/heads/wd-v1.0/vo-dml/mango.vo-dml.xml" | ||
| #: VODML URL of the `Photometry Data Model <https://www.ivoa.net/documents/PHOTDM/20221101/index.html>`_ | ||
| Phot = "https://ivoa.net/xml/VODML/Phot-v1.vodml.xml" | ||
| #: VODML URL of the `Astronomical Coordinates and Coordinate Systems | ||
| #: <https://www.ivoa.net/documents/Coords/20221004/index.html>`_ datamodel | ||
| coords = "https://ivoa.net/xml/VODML/Coords-v1.vo-dml.xml" | ||
| #: VODML URL of the `Astronomical Measurements Model | ||
| #: <https://www.ivoa.net/documents/Meas/20221004/index.html>`_ | ||
| meas = "https://ivoa.net/xml/VODML/Meas-v1.vo-dml.xml" | ||
| class EpochPositionAutoMapping: | ||
| """ | ||
| Expected UCDs for identifying FIELD to be mapped to EpochPosition attributes. | ||
| - UCD-s of the associated errors are derived from them | ||
| - list items must have an exact match | ||
| - Single values are evaluated as starting with | ||
| """ | ||
| #: UCD-s accepted to map the longitude | ||
| longitude = ["POS_EQ_RA_MAIN", "pos.eq.ra;meta.main"] | ||
| #: UCD-s accepted to map the latitude | ||
| latitude = ["POS_EQ_DEC_MAIN", "pos.eq.dec;meta.main"] | ||
| #: UCD-s accepted to map the proper motion longitude | ||
| pmLongitude = ["pos.pm;pos.eq.ra"] | ||
| #: UCD-s accepted to map the proper motion latitude | ||
| pmLatitude = ["pos.pm;pos.eq.dec"] | ||
| #: UCD-s accepted to map the obsDate | ||
| obsDate = ["time.epoch;obs;stat.mean", "time.epoch;obs"] | ||
| #: UCD-s accepted to map the parallax | ||
| parallax = ["pos.parallax.trig"] | ||
| #: first word of UCD-s accepted to map the radial velocity | ||
| radialVelocity = "spect.dopplerVeloc.opt" |
| from contextlib import contextmanager | ||
| import pytest | ||
| import requests_mock | ||
| class ContextAdapter(requests_mock.Adapter): | ||
| """ | ||
| requests_mock adapter where ``register_uri`` returns a context manager | ||
| """ | ||
| @contextmanager | ||
| def register_uri(self, *args, **kwargs): | ||
| matcher = super().register_uri(*args, **kwargs) | ||
| yield matcher | ||
| self.remove_matcher(matcher) | ||
| def remove_matcher(self, matcher): | ||
| if matcher in self._matchers: | ||
| self._matchers.remove(matcher) | ||
| @pytest.fixture(scope='function') | ||
| def mocker(): | ||
| with requests_mock.Mocker( | ||
| adapter=ContextAdapter(case_sensitive=True) | ||
| ) as mocker_ins: | ||
| yield mocker_ins |
| <?xml version="1.0"?> | ||
| <INSTANCE dmrole="" dmtype="Phot:PhotCal"> | ||
| <ATTRIBUTE dmrole="Phot:PhotCal.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grp/AB" /> | ||
| <INSTANCE dmrole="Phot:PhotCal.zeroPoint" dmtype="Phot:ZeroPoint"> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.type" dmtype="ivoa:integer" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeValue" dmtype="ivoa:real" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeError" dmtype="ivoa:real" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.softeningParameter" dmtype="ivoa:real" value="" /> | ||
| <INSTANCE dmrole="Phot:ZeroPoint.flux" dmtype="Phot:Flux"> | ||
| <ATTRIBUTE dmrole="Phot:Flux.ucd" dmtype="Phot:UCD" value="phot.flux.density" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.unitexpression" dmtype="ivoa:Unit" value="Jy" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.value" dmtype="ivoa:real" value="3631" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.error" dmtype="ivoa:real" value="0" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.magnitudeSystem" dmtype="Phot:MagnitudeSystem"> | ||
| <ATTRIBUTE dmrole="Phot:MagnitudeSystem.type" dmtype="Phot:TypeOfMagSystem" value="AB" /> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter" dmtype="Phot:photometryFilter"> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.fpsIdentifier" dmtype="ivoa:string" value="ivo://svo/fps" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grp" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.name" dmtype="ivoa:string" value="GAIA3.Grp" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.description" dmtype="ivoa:string" value="GAIA Grp filter, DR3" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.bandName" dmtype="ivoa:string" value="" /> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter.bandwidth" dmtype="Phot:Bandwidth"> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.ucd" dmtype="Phot:UCD" value="instr.bandwidth" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.unitexpression" dmtype="ivoa:Unit" value="" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.extent" dmtype="ivoa:real" value="2924.4362576966" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.start" dmtype="ivoa:real" value="6200.4566154641" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.stop" dmtype="ivoa:real" value="6200.4566154641" /> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.transmissionCurve" dmtype="Phot:TransmissionCurve"> | ||
| <INSTANCE dmrole="Phot:TransmissionCurve.access" dmtype="Phot:Access"> | ||
| <ATTRIBUTE dmrole="Phot:Access.reference" dmtype="ivoa:anyURI" | ||
| value="http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=GAIA/GAIA3.Grp" /> | ||
| <ATTRIBUTE dmrole="Phot:Access.size" dmtype="ivoa:integer" value="10" /> | ||
| <ATTRIBUTE dmrole="Phot:Access.format" dmtype="ivoa:string" value="application/x-votable+xml" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.spectralLocation" dmtype="Phot:SpectralLocation"> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.ucd" dmtype="Phot:UCD" value="em.wl;meta.main" /> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.unitexpression" dmtype="ivoa:Unit" value="Angstrom" /> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.value" dmtype="ivoa:real" value="7769.0226260418" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> |
| <?xml version="1.0"?> | ||
| <INSTANCE dmrole="" dmtype="Phot:PhotCal"> | ||
| <ATTRIBUTE dmrole="Phot:PhotCal.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grvs/AB" /> | ||
| <INSTANCE dmrole="Phot:PhotCal.zeroPoint" dmtype="Phot:ZeroPoint"> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.type" dmtype="ivoa:integer" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeValue" dmtype="ivoa:real" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeError" dmtype="ivoa:real" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.softeningParameter" dmtype="ivoa:real" value="" /> | ||
| <INSTANCE dmrole="Phot:ZeroPoint.flux" dmtype="Phot:Flux"> | ||
| <ATTRIBUTE dmrole="Phot:Flux.ucd" dmtype="Phot:UCD" value="phot.flux.density" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.unitexpression" dmtype="ivoa:Unit" value="Jy" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.value" dmtype="ivoa:real" value="3631" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.error" dmtype="ivoa:real" value="0" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.magnitudeSystem" dmtype="Phot:MagnitudeSystem"> | ||
| <ATTRIBUTE dmrole="Phot:MagnitudeSystem.type" dmtype="Phot:TypeOfMagSystem" value="AB" /> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter" dmtype="Phot:photometryFilter"> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.fpsIdentifier" dmtype="ivoa:string" value="ivo://svo/fps" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grvs" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.name" dmtype="ivoa:string" value="GAIA3.Grvs" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.description" dmtype="ivoa:string" value="GAIA Grvs filter, DR3" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.bandName" dmtype="ivoa:string" value="" /> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter.bandwidth" dmtype="Phot:Bandwidth"> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.ucd" dmtype="Phot:UCD" value="instr.bandwidth" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.unitexpression" dmtype="ivoa:Unit" value="" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.extent" dmtype="ivoa:real" value="235.1243119935" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.start" dmtype="ivoa:real" value="8459.7502595805" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.stop" dmtype="ivoa:real" value="8459.7502595805" /> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.transmissionCurve" dmtype="Phot:TransmissionCurve"> | ||
| <INSTANCE dmrole="Phot:TransmissionCurve.access" dmtype="Phot:Access"> | ||
| <ATTRIBUTE dmrole="Phot:Access.reference" dmtype="ivoa:anyURI" | ||
| value="http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=GAIA/GAIA3.Grvs" /> | ||
| <ATTRIBUTE dmrole="Phot:Access.size" dmtype="ivoa:integer" value="24" /> | ||
| <ATTRIBUTE dmrole="Phot:Access.format" dmtype="ivoa:string" value="application/x-votable+xml" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.spectralLocation" dmtype="Phot:SpectralLocation"> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.ucd" dmtype="Phot:UCD" value="em.wl;meta.main" /> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.unitexpression" dmtype="ivoa:Unit" value="Angstrom" /> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.value" dmtype="ivoa:real" value="8578.7613420633" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> |
| <VODML xmlns="http://www.ivoa.net/xml/mivot"> | ||
| <REPORT status="OK"/> | ||
| <MODEL name="ivoa" url="https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml"/> | ||
| <MODEL name="mango" url="https://raw.githubusercontent.com/ivoa-std/MANGO/refs/heads/wd-v1.0/vo-dml/mango.vo-dml.xml"/> | ||
| <MODEL name="Phot" url="https://ivoa.net/xml/VODML/Phot-v1.vodml.xml"/> | ||
| <MODEL name="coords" url="https://ivoa.net/xml/VODML/Coords-v1.vo-dml.xml"/> | ||
| <GLOBALS> | ||
| <INSTANCE dmtype="mango:origin.QueryOrigin" dmid="_origin"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.service_protocol" value="ASU"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.request_date" value="2024-03-21T15:16:08"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.request" value="https://vizier.cds.unistra.fr/viz-bin/votable?-oc.form=dec&amp;-out.max=5&amp;-out.add=_r&amp;-out.add=_RAJ,_DEJ&amp;-sort=_r&amp;-c.eq=J2000&amp;-c.r= 2&amp;-c.u=arcmin&amp;-c.geom=r&amp;-source=I/355/gaiadr3&amp;-order=I&amp;-out.orig=standard&amp;-out=DR3Name&amp;-out=RA_ICRS&amp;-out=DE_ICRS&amp;-out=Source&amp;-out=e_RA_ICRS&amp;-out=e_DE_ICRS&amp;-out=Plx&amp;-out=e_Plx&amp;-out=PM&amp;-out=pmRA&amp;-out=e_pmRA&amp;-out=pmDE&amp;-out=e_pmDE&amp;-out=RADEcor&amp;-out=RAPlxcor&amp;-out=RApmRAcor&amp;-out=RApmDEcor&amp;-out=DEPlxcor&amp;-out=DEpmRAcor&amp;-out=DEpmDEcor&amp;-out=PlxpmRAcor&amp;-out=PlxpmDEcor&amp;-out=pmRApmDEcor&amp;-out=RV&amp;-out=e_RV&amp;-out=Vbroad&amp;-out=GRVSmag&amp;-out=QSO&amp;-out=Gal&amp;-out=NSS&amp;-out=XPcont&amp;-out=XPsamp&amp;-out=RVS&amp;-out=EpochPh&amp;-out=EpochRV&amp;-out=MCMCGSP&amp;-out=MCMCMSC&amp;-out=And&amp;-out=Teff&amp;-out=logg&amp;-out=[Fe/H]&amp;-out=Dist&amp;-out=A0&amp;-out=HIP&amp;-out=PS1&amp;-out=SDSS13&amp;-out=SKYM2&amp;-out=TYC2&amp;-out=URAT1&amp;-out=AllWISE&amp;-out=APASS9&amp;-out=GSC23&amp;-out=RAVE5&amp;-out=2MASS&amp;-out=RAVE6&amp;-out=RAJ2000&amp;-out=DEJ2000&amp;"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.contact" value="cds-question@unistra.fr"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.server_software" value="7.33.3"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.publisher" value="CDS"/> | ||
| <COLLECTION dmrole="mango:origin.QueryOrigin.dataOrigin"> | ||
| <INSTANCE dmtype="mango:origin.DataOrigin"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.ivoid" value="ivo://cds.vizier/i/355"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.cites" value="bibcode:2022yCat.1355....0G, doi:10.26093/cds/vizier.1355"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.original_date" value="2022"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.reference_url" value="https://cdsarc.cds.unistra.fr/viz-bin/cat/I/355"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.rights_uri" value="https://cds.unistra.fr/vizier-org/licences_vizier.html"/> | ||
| <COLLECTION dmrole="mango:origin.DataOrigin.articles"> | ||
| <INSTANCE dmtype="mango:origin.Article"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.Article.identifier" value="doi:10.1051/0004-6361/202039657e]"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.Article.editor" value="A&A"/> | ||
| </INSTANCE> | ||
| </COLLECTION> | ||
| <COLLECTION dmrole="mango:origin.DataOrigin.creators"> | ||
| <ATTRIBUTE dmtype="ivoa:string" value="Gaia collaboration"/> | ||
| </COLLECTION> | ||
| </INSTANCE> | ||
| </COLLECTION> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="Phot:PhotCal" dmid="_photcal_GAIA_GAIA3_Grvs_AB"> | ||
| <ATTRIBUTE dmrole="Phot:PhotCal.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grvs/AB"/> | ||
| <INSTANCE dmrole="Phot:PhotCal.zeroPoint" dmtype="Phot:ZeroPoint"> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.type" dmtype="ivoa:integer" value="0"/> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeValue" dmtype="ivoa:real" value="0"/> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeError" dmtype="ivoa:real" value="0"/> | ||
| <!-- ATTRIBUTE dmrole="Phot:ZeroPoint.softeningParameter" dmtype="ivoa:real" value=""/ --> | ||
| <INSTANCE dmrole="Phot:ZeroPoint.flux" dmtype="Phot:Flux"> | ||
| <ATTRIBUTE dmrole="Phot:Flux.ucd" dmtype="Phot:UCD" value="phot.flux.density"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.unitexpression" dmtype="ivoa:Unit" value="Jy"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.value" dmtype="ivoa:real" value="3631"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.error" dmtype="ivoa:real" value="0"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.magnitudeSystem" dmtype="Phot:MagnitudeSystem"> | ||
| <ATTRIBUTE dmrole="Phot:MagnitudeSystem.type" dmtype="Phot:TypeOfMagSystem" value="AB"/> | ||
| </INSTANCE> | ||
| <REFERENCE dmrole="Phot:PhotCal.photometryFilter" dmref="_photfilter_GAIA_GAIA3_Grvs_AB"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="Phot:PhotometryFilter" dmid="_photfilter_GAIA_GAIA3_Grvs_AB"> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.fpsIdentifier" dmtype="ivoa:string" value="ivo://svo/fps"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grvs"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.name" dmtype="ivoa:string" value="GAIA3.Grvs"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.description" dmtype="ivoa:string" value="GAIA Grvs filter, DR3"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.bandName" dmtype="ivoa:string" value=""/> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.bandwidth" dmtype="Phot:Bandwidth"> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.ucd" dmtype="Phot:UCD" value="instr.bandwidth"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.unitexpression" dmtype="ivoa:Unit" value=""/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.extent" dmtype="ivoa:real" value="235.1243119935"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.start" dmtype="ivoa:real" value="8459.7502595805"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.stop" dmtype="ivoa:real" value="8459.7502595805"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.transmissionCurve" dmtype="Phot:TransmissionCurve"> | ||
| <INSTANCE dmrole="Phot:TransmissionCurve.access" dmtype="Phot:Access"> | ||
| <ATTRIBUTE dmrole="Phot:Access.reference" dmtype="ivoa:anyURI" value="http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=GAIA/GAIA3.Grvs"/> | ||
| <ATTRIBUTE dmrole="Phot:Access.size" dmtype="ivoa:integer" value="24"/> | ||
| <ATTRIBUTE dmrole="Phot:Access.format" dmtype="ivoa:string" value="application/x-votable+xml"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.spectralLocation" dmtype="Phot:SpectralLocation"> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.ucd" dmtype="Phot:UCD" value="em.wl;meta.main"/> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.unitexpression" dmtype="ivoa:Unit" value="Angstrom"/> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.value" dmtype="ivoa:real" value="8578.7613420633"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="Phot:PhotCal" dmid="_photcal_GAIA_GAIA3_Grp_AB"> | ||
| <ATTRIBUTE dmrole="Phot:PhotCal.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grp/AB"/> | ||
| <INSTANCE dmrole="Phot:PhotCal.zeroPoint" dmtype="Phot:ZeroPoint"> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.type" dmtype="ivoa:integer" value="0"/> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeValue" dmtype="ivoa:real" value="0"/> | ||
| <ATTRIBUTE dmrole="Phot:ZeroPoint.referenceMagnitudeError" dmtype="ivoa:real" value="0"/> | ||
| <!-- ATTRIBUTE dmrole="Phot:ZeroPoint.softeningParameter" dmtype="ivoa:real" value=""/ --> | ||
| <INSTANCE dmrole="Phot:ZeroPoint.flux" dmtype="Phot:Flux"> | ||
| <ATTRIBUTE dmrole="Phot:Flux.ucd" dmtype="Phot:UCD" value="phot.flux.density"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.unitexpression" dmtype="ivoa:Unit" value="Jy"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.value" dmtype="ivoa:real" value="3631"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.error" dmtype="ivoa:real" value="0"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.magnitudeSystem" dmtype="Phot:MagnitudeSystem"> | ||
| <ATTRIBUTE dmrole="Phot:MagnitudeSystem.type" dmtype="Phot:TypeOfMagSystem" value="AB"/> | ||
| </INSTANCE> | ||
| <REFERENCE dmrole="Phot:PhotCal.photometryFilter" dmref="_photfilter_GAIA_GAIA3_Grp_AB"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="Phot:PhotometryFilter" dmid="_photfilter_GAIA_GAIA3_Grp_AB"> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.fpsIdentifier" dmtype="ivoa:string" value="ivo://svo/fps"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.identifier" dmtype="ivoa:string" value="GAIA/GAIA3.Grp"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.name" dmtype="ivoa:string" value="GAIA3.Grp"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.description" dmtype="ivoa:string" value="GAIA Grp filter, DR3"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.bandName" dmtype="ivoa:string" value=""/> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.bandwidth" dmtype="Phot:Bandwidth"> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.ucd" dmtype="Phot:UCD" value="instr.bandwidth"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.unitexpression" dmtype="ivoa:Unit" value=""/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.extent" dmtype="ivoa:real" value="2924.4362576966"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.start" dmtype="ivoa:real" value="6200.4566154641"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.stop" dmtype="ivoa:real" value="6200.4566154641"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.transmissionCurve" dmtype="Phot:TransmissionCurve"> | ||
| <INSTANCE dmrole="Phot:TransmissionCurve.access" dmtype="Phot:Access"> | ||
| <ATTRIBUTE dmrole="Phot:Access.reference" dmtype="ivoa:anyURI" value="http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=GAIA/GAIA3.Grp"/> | ||
| <ATTRIBUTE dmrole="Phot:Access.size" dmtype="ivoa:integer" value="10"/> | ||
| <ATTRIBUTE dmrole="Phot:Access.format" dmtype="ivoa:string" value="application/x-votable+xml"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.spectralLocation" dmtype="Phot:SpectralLocation"> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.ucd" dmtype="Phot:UCD" value="em.wl;meta.main"/> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.unitexpression" dmtype="ivoa:Unit" value="Angstrom"/> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.value" dmtype="ivoa:real" value="7769.0226260418"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="coords:SpaceSys" dmid="_spaceframe_spaceRefFrame_equinox_refPosition"> | ||
| <INSTANCE dmtype="coords:SpaceFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:SpaceFrame.spaceRefFrame" value="spaceRefFrame"/> | ||
| <ATTRIBUTE dmtype="coords:Epoch" dmrole="coords:SpaceFrame.equinox" value="equinox"/> | ||
| <INSTANCE dmtype="coords:StdRefLocation" dmrole="coords:SpaceFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:StdRefLocation.position" value="refPosition"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="coords:TimeSys" dmid="_timeframe_TCB_BARYCENTER"> | ||
| <INSTANCE dmtype="coords:TimeFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:TimeFrame.timescale" value="TCB"/> | ||
| <INSTANCE dmtype="coords:StdRefLocation" dmrole="coords:TimeFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:StdRefLocation.position" value="BARYCENTER"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </GLOBALS> | ||
| <TEMPLATES> | ||
| <INSTANCE dmtype="mango:MangoObject" dmid="DR3Name"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:MangoObject.identifier" ref="DR3Name"/> | ||
| <REFERENCE dmrole="mango:MangoObject.queryOrigin" dmref="_origin"/> | ||
| <COLLECTION dmrole="mango:MangoObject.propertyDock"> | ||
| <INSTANCE dmtype="mango:Color"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:Property.description" value="very nice color"/> | ||
| <INSTANCE dmtype="mango:VocabularyTerm" dmrole="mango:Property.semantics"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.uri" value="vocabulary#term"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.label" value="term"/> | ||
| </INSTANCE> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:PhotometricProperty.value" value="8.76"/> | ||
| <INSTANCE dmtype="mango:error.PErrorAsym1D" dmrole="mango:PhotometricProperty.error"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorAsym1D.low" value="1"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorAsym1D.high" value="3"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:ColorDef" dmrole="mango:Color.colorDef"> | ||
| <ATTRIBUTE dmtype="mango:ColorDefinition" dmrole="mango:ColorDef.definition" value="ColorIndex"/> | ||
| <REFERENCE dmrole="mango:ColorDef.low" dmref="_photfilter_GAIA_GAIA3_Grvs_AB"/> | ||
| <REFERENCE dmrole="mango:ColorDef.high" dmref="_photfilter_GAIA_GAIA3_Grp_AB"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:Brightness"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:Property.description" value="Grvs magnitude"/> | ||
| <INSTANCE dmtype="mango:VocabularyTerm" dmrole="mango:Property.semantics"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.uri" value="https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#magnitude"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.label" value="magnitude"/> | ||
| </INSTANCE> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:PhotometricProperty.value" unit="mag" ref="GRVSmag"/> | ||
| <INSTANCE dmtype="mango:error.PErrorAsym1D" dmrole="mango:PhotometricProperty.error"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorAsym1D.low" value="1"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorAsym1D.high" value="3"/> | ||
| </INSTANCE> | ||
| <REFERENCE dmrole="mango:Brightness.photCal" dmref="_photcal_GAIA_GAIA3_Grvs_AB"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:EpochPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:Property.description" value="6 parameters position"/> | ||
| <INSTANCE dmtype="mango:VocabularyTerm" dmrole="mango:Property.semantics"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.uri" value="https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#astronomical-location"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.label" value="Astronomical location"/> | ||
| </INSTANCE> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.longitude" unit="deg" ref="_RAJ2000"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.latitude" unit="deg" ref="_DEJ2000"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.pmLongitude" unit="mas / yr" ref="pmRA"/> | ||
| <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> | ||
| <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"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.latitudePmLongitude" ref="DEpmRAcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.latitudePmLatitude" ref="DEpmDEcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.longitudePmLongitude" ref="RApmRAcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.longitudePmLatitude" ref="RApmDEcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.longitudeParallax" ref="RAPlxcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.latitudeParallax" ref="DEPlxcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.pmLongitudeParallax" ref="PlxpmRAcor"/> | ||
| <ATTRIBUTE dmtype="ivoa:real" dmrole="mango:EpochPositionCorrelations.pmLatitudeParallax" ref="PlxpmDEcor"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:EpochPositionErrors" dmrole="mango:EpochPosition.errors"> | ||
| <INSTANCE dmtype="mango:error.PErrorSym2D" dmrole="mango:EpochPositionErrors.position"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma1" unit="mas" ref="e_RA_ICRS"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma2" unit="mas" ref="e_DE_ICRS"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:error.PErrorSym2D" dmrole="mango:EpochPositionErrors.properMotion"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma1" unit="mas / yr" ref="e_pmRA"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma2" unit="mas / yr" ref="e_pmDE"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:error.PErrorSym1D" dmrole="mango:EpochPositionErrors.parallax"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym1D.sigma" unit="mas" ref="e_Plx"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:error.PErrorSym1D" dmrole="mango:EpochPositionErrors.radialVelocity"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym1D.sigma" unit="km / s" ref="e_RV"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <REFERENCE dmrole="mango:EpochPosition.spaceSys" dmref="_spaceframe_spaceRefFrame_equinox_refPosition"/> | ||
| <REFERENCE dmrole="mango:EpochPosition.timeSys" dmref="_timeframe_TCB_BARYCENTER"/> | ||
| </INSTANCE> | ||
| </COLLECTION> | ||
| </INSTANCE> | ||
| </TEMPLATES> | ||
| </VODML> |
| <VODML xmlns="http://www.ivoa.net/xml/mivot"> | ||
| <REPORT status="OK"/> | ||
| <MODEL name="ivoa" url="https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml"/> | ||
| <MODEL name="coords" url="https://ivoa.net/xml/VODML/Coords-v1.vo-dml.xml"/> | ||
| <MODEL name="mango" url="https://raw.githubusercontent.com/ivoa-std/MANGO/refs/heads/wd-v1.0/vo-dml/mango.vo-dml.xml"/> | ||
| <GLOBALS> | ||
| <INSTANCE dmtype="coords:SpaceSys" dmid="_spaceframe_ICRS_BARYCENTER"> | ||
| <INSTANCE dmtype="coords:SpaceFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:SpaceFrame.spaceRefFrame" value="ICRS"/> | ||
| <INSTANCE dmtype="coords:CustomRefLocation" dmrole="coords:SpaceFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:CustomRefLocation.position" value="BARYCENTER"/> | ||
| <ATTRIBUTE dmtype="coords:Epoch" dmrole="coords:CustomRefLocation.epoch" value="2016.000"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="coords:SpaceSys" dmid="_spaceframe_eq_FK5_J2000_BARYCENTER"> | ||
| <INSTANCE dmtype="coords:SpaceFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:SpaceFrame.spaceRefFrame" value="eq_FK5"/> | ||
| <ATTRIBUTE dmtype="coords:Epoch" dmrole="coords:SpaceFrame.equinox" value="J2000"/> | ||
| <INSTANCE dmtype="coords:StdRefLocation" dmrole="coords:SpaceFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:StdRefLocation.position" value="BARYCENTER"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:origin.QueryOrigin" dmid="_origin"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.service_protocol" value="ASU"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.request_date" value="2024-03-21T15:16:08"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.request" value="https://vizier.cds.unistra.fr/viz-bin/votable?-oc.form=dec&-out.max=5&-out.add=_r&-out.add=_RAJ,_DEJ&-sort=_r&-c.eq=J2000&-c.r= 2&-c.u=arcmin&-c.geom=r&-source=I/355/gaiadr3&-order=I&-out.orig=standard&-out=DR3Name&-out=RA_ICRS&-out=DE_ICRS&-out=Source&-out=e_RA_ICRS&-out=e_DE_ICRS&-out=Plx&-out=e_Plx&-out=PM&-out=pmRA&-out=e_pmRA&-out=pmDE&-out=e_pmDE&-out=RADEcor&-out=RAPlxcor&-out=RApmRAcor&-out=RApmDEcor&-out=DEPlxcor&-out=DEpmRAcor&-out=DEpmDEcor&-out=PlxpmRAcor&-out=PlxpmDEcor&-out=pmRApmDEcor&-out=RV&-out=e_RV&-out=Vbroad&-out=GRVSmag&-out=QSO&-out=Gal&-out=NSS&-out=XPcont&-out=XPsamp&-out=RVS&-out=EpochPh&-out=EpochRV&-out=MCMCGSP&-out=MCMCMSC&-out=And&-out=Teff&-out=logg&-out=[Fe/H]&-out=Dist&-out=A0&-out=HIP&-out=PS1&-out=SDSS13&-out=SKYM2&-out=TYC2&-out=URAT1&-out=AllWISE&-out=APASS9&-out=GSC23&-out=RAVE5&-out=2MASS&-out=RAVE6&-out=RAJ2000&-out=DEJ2000&"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.contact" value="cds-question@unistra.fr"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.server_software" value="7.33.3"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.QueryOrigin.publisher" value="CDS"/> | ||
| <COLLECTION dmrole="mango:origin.QueryOrigin.dataOrigin"> | ||
| <INSTANCE dmtype="mango:origin.DataOrigin"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.ivoid" value="ivo://cds.vizier/i/355"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.cites" value="bibcode:2022yCat.1355....0G"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.original_date" value="2022"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.reference_url" value="https://cdsarc.cds.unistra.fr/viz-bin/cat/I/355"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:origin.DataOrigin.rights_uri" value="https://cds.unistra.fr/vizier-org/licences_vizier.html"/> | ||
| <COLLECTION dmrole="mango:origin.DataOrigin.creators"> | ||
| <ATTRIBUTE dmtype="ivoa:string" value="Gaia collaboration"/> | ||
| </COLLECTION> | ||
| </INSTANCE> | ||
| </COLLECTION> | ||
| </INSTANCE> | ||
| </GLOBALS> | ||
| <TEMPLATES> | ||
| <INSTANCE dmtype="mango:MangoObject" dmid="URAT1"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:MangoObject.identifier" ref="URAT1"/> | ||
| <REFERENCE dmrole="mango:MangoObject.queryOrigin" dmref="_origin"/> | ||
| <COLLECTION dmrole="mango:MangoObject.propertyDock"> | ||
| <INSTANCE dmtype="mango:EpochPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:Property.description" value="6 parameters position"/> | ||
| <INSTANCE dmtype="mango:VocabularyTerm" dmrole="mango:Property.semantics"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.uri" value="https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#astronomical-location"/> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="mango:VocabularyTerm.label" value="Astronomical location"/> | ||
| </INSTANCE> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.longitude" unit="deg" ref="RA_ICRS"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.latitude" unit="deg" ref="DE_ICRS"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.parallax" unit="mas" ref="Plx"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.pmLongitude" unit="mas / yr" ref="pmRA"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.pmLatitude" unit="mas / yr" ref="pmDE"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.radialVelocity" unit="km / s" ref="RV"/> | ||
| <INSTANCE dmtype="mango:EpochPositionCorrelations" dmrole="mango:EpochPosition.correlations"> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:EpochPositionErrors" dmrole="mango:EpochPosition.errors"> | ||
| <INSTANCE dmtype="mango:error.PErrorSym2D" dmrole="mango:EpochPositionErrors.position"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma1" unit="mas" ref="e_RA_ICRS"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma2" unit="mas" ref="e_DE_ICRS"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:error.PErrorSym1D" dmrole="mango:EpochPositionErrors.parallax"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym1D.sigma" unit="mas" ref="e_Plx"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:error.PErrorSym2D" dmrole="mango:EpochPositionErrors.properMotion"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma1" unit="mas / yr" ref="e_pmRA"/> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym2D.sigma2" unit="mas / yr" ref="e_pmDE"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="mango:error.PErrorSym1D" dmrole="mango:EpochPositionErrors.radialVelocity"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.PErrorSym1D.sigma" unit="km / s" ref="e_RV"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <REFERENCE dmrole="mango:EpochPosition.spaceSys" dmref="_spaceframe_ICRS_BARYCENTER"/> | ||
| </INSTANCE> | ||
| </COLLECTION> | ||
| </INSTANCE> | ||
| </TEMPLATES> | ||
| </VODML> |
| <VODML xmlns="http://www.ivoa.net/xml/mivot"> | ||
| <REPORT status="OK">Generated by pyvo.mivot.writer</REPORT> | ||
| <MODEL name="ivoa" url="https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml" /> | ||
| <MODEL name="coords" url="https://www.ivoa.net/xml/STC/20200908/Coords-v1.0.vo-dml.xml" /> | ||
| <GLOBALS> | ||
| <INSTANCE dmtype="coords:SpaceSys" dmid="_spaceframe_FK5_J2000_BARYCENTER"> | ||
| <INSTANCE dmtype="coords:SpaceFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:SpaceFrame.spaceRefFrame" value="FK5" /> | ||
| <ATTRIBUTE dmtype="coords:Epoch" dmrole="coords:SpaceFrame.equinox" value="J2000" /> | ||
| <INSTANCE dmtype="coords:StdRefLocation" dmrole="coords:SpaceFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:StdRefLocation.position" value="BARYCENTER" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="coords:TimeSys" dmid="_timeframe_TCB_BARYCENTER"> | ||
| <INSTANCE dmtype="coords:TimeFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:TimeFrame.timescale" value="TCB" /> | ||
| <INSTANCE dmtype="coords:StdRefLocation" dmrole="coords:TimeFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:StdRefLocation.position" value="BARYCENTER" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </GLOBALS> | ||
| </VODML> |
| <VODML xmlns="http://www.ivoa.net/xml/mivot"> | ||
| <REPORT status="OK">Generated by pyvo.mivot.writer</REPORT> | ||
| <MODEL name="ivoa" url="https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml" /> | ||
| <MODEL name="Phot" url="https://ivoa.net/xml/VODML/Phot-v1.vodml.xml" /> | ||
| <GLOBALS> | ||
| <INSTANCE dmtype="Phot:PhotCal" dmid="_photcal_SLOAN_SDSS_g_AB"> | ||
| <ATTRIBUTE dmrole="Phot:PhotCal.identifier" dmtype="ivoa:string" value="SLOAN/SDSS.g/AB" /> | ||
| <INSTANCE dmrole="Phot:PhotCal.zeroPoint" dmtype="Phot:AsinhZeroPoint"> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.type" dmtype="ivoa:integer" value="1" /> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.referenceMagnitudeValue" dmtype="ivoa:real" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.referenceMagnitudeError" dmtype="ivoa:real" value="0" /> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.softeningParameter" dmtype="ivoa:real" value="0.00000000009" /> | ||
| <INSTANCE dmrole="Phot:AsinhZeroPoint.flux" dmtype="Phot:Flux"> | ||
| <ATTRIBUTE dmrole="Phot:Flux.ucd" dmtype="Phot:UCD" value="phot.flux.density" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.unitexpression" dmtype="ivoa:Unit" value="Jy" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.value" dmtype="ivoa:real" value="3631" /> | ||
| <ATTRIBUTE dmrole="Phot:Flux.error" dmtype="ivoa:real" value="0" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.magnitudeSystem" dmtype="Phot:MagnitudeSystem"> | ||
| <ATTRIBUTE dmrole="Phot:MagnitudeSystem.type" dmtype="Phot:TypeOfMagSystem" value="AB" /> | ||
| </INSTANCE> | ||
| <REFERENCE dmrole="Phot:PhotCal.photometryFilter" dmref="_photfilter_SLOAN_SDSS_g_AB" /> | ||
| </INSTANCE> | ||
| <INSTANCE dmtype="Phot:photometryFilter" dmid="_photfilter_SLOAN_SDSS_g_AB"> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.fpsIdentifier" dmtype="ivoa:string" value="ivo://svo/fps" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.identifier" dmtype="ivoa:string" value="SLOAN/SDSS.g" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.name" dmtype="ivoa:string" value="SDSS.g" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.description" dmtype="ivoa:string" value="SDSS g full transmission" /> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.bandName" dmtype="ivoa:string" value="g" /> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter.bandwidth" dmtype="Phot:Bandwidth"> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.ucd" dmtype="Phot:UCD" value="instr.bandwidth" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.unitexpression" dmtype="ivoa:Unit" value="" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.extent" dmtype="ivoa:real" value="1064.6831251068" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.start" dmtype="ivoa:real" value="3797.6384743979" /> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.stop" dmtype="ivoa:real" value="3797.6384743979" /> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.transmissionCurve" dmtype="Phot:TransmissionCurve"> | ||
| <INSTANCE dmrole="Phot:TransmissionCurve.access" dmtype="Phot:Access"> | ||
| <ATTRIBUTE dmrole="Phot:Access.reference" dmtype="ivoa:anyURI" | ||
| value="http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=SLOAN/SDSS.g" /> | ||
| <ATTRIBUTE dmrole="Phot:Access.size" dmtype="ivoa:integer" value="2" /> | ||
| <ATTRIBUTE dmrole="Phot:Access.format" dmtype="ivoa:string" value="application/x-votable+xml" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.spectralLocation" dmtype="Phot:SpectralLocation"> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.ucd" dmtype="Phot:UCD" value="em.wl;meta.main" /> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.unitexpression" dmtype="ivoa:Unit" value="Angstrom" /> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.value" dmtype="ivoa:real" value="4702.4953002767" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </GLOBALS> | ||
| </VODML> |
| { | ||
| "dmtype": "mango:EpochPosition", | ||
| "longitude": { | ||
| "value": 52.2340018, | ||
| "unit": "deg" | ||
| }, | ||
| "latitude": { | ||
| "value": 59.8937333, | ||
| "unit": "deg" | ||
| }, | ||
| "errors": { | ||
| "dmtype": "mango:EpochPositionErrors", | ||
| "dmrole": "mango:EpochPosition.errors", | ||
| "position": { | ||
| "dmtype": "mango:error.ErrorCorrMatrix", | ||
| "dmrole": "mango:EpochPositionErrors.position", | ||
| "sigma1": { | ||
| "value": 6.0, | ||
| "unit": "arcsec" | ||
| }, | ||
| "sigma2": { | ||
| "value": 6.0, | ||
| "unit": "arcsec" | ||
| } | ||
| } | ||
| }, | ||
| "spaceSys": { | ||
| "dmtype": "coords:SpaceSys", | ||
| "dmid": "_spacesys_icrs", | ||
| "dmrole": "mango:EpochPosition.spaceSys", | ||
| "frame": { | ||
| "dmtype": "coords:SpaceFrame", | ||
| "dmrole": "coords:PhysicalCoordSys.frame", | ||
| "spaceRefFrame": { | ||
| "value": "ICRS" | ||
| }, | ||
| "refPosition": { | ||
| "dmtype": "coords:StdRefLocation", | ||
| "dmrole": "coords:SpaceFrame.refPosition", | ||
| "position": { | ||
| "value": "BARYCENTER" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| <VODML xmlns="http://www.ivoa.net/xml/mivot"> | ||
| <REPORT status="OK">Mivot writer unit test</REPORT> | ||
| <MODEL name="ivoa" url="https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml" /> | ||
| <MODEL name="coords" url="https://www.ivoa.net/xml/STC/20200908/Coords-v1.0.vo-dml.xml" /> | ||
| <MODEL name="mango" url="https://raw.githubusercontent.com/lmichel/MANGO/draft-0.1/vo-dml/mango.vo-dml.xml" /> | ||
| <GLOBALS> | ||
| <INSTANCE dmtype="coords:SpaceSys" dmid="_spacesys_icrs"> | ||
| <INSTANCE dmtype="coords:SpaceFrame" dmrole="coords:PhysicalCoordSys.frame"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:SpaceFrame.spaceRefFrame" value="ICRS" /> | ||
| <INSTANCE dmtype="coords:StdRefLocation" dmrole="coords:SpaceFrame.refPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:string" dmrole="coords:StdRefLocation.position" value="BARYCENTER" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </GLOBALS> | ||
| <TEMPLATES> | ||
| <INSTANCE dmtype="mango:EpochPosition"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.longitude" unit="deg" ref="RAICRS" /> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:EpochPosition.latitude" unit="deg" ref="DEICRS" /> | ||
| <REFERENCE dmrole="mango:EpochPosition.spaceSys" dmref="_spacesys_icrs" /> | ||
| <INSTANCE dmtype="mango:EpochPositionErrors" dmrole="mango:EpochPosition.errors"> | ||
| <INSTANCE dmtype="mango:error.ErrorCorrMatrix" dmrole="mango:EpochPositionErrors.position"> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.ErrorCorrMatrix.sigma1" unit="arcsec" ref="sigm" /> | ||
| <ATTRIBUTE dmtype="ivoa:RealQuantity" dmrole="mango:error.ErrorCorrMatrix.sigma2" unit="arcsec" ref="sigm" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </TEMPLATES> | ||
| </VODML> |
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xmlns="http://www.ivoa.net/xml/VOTable/v1.3" | ||
| xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/v1.3"> | ||
| <DESCRIPTION> | ||
| VizieR Astronomical Server vizier.cds.unistra.fr | ||
| Date: 2024-03-21T15:16:08 [V7.33.3] | ||
| Explanations and Statistics of | ||
| UCDs: See LINK below | ||
| In case of problem, please report to: cds-question@unistra.fr | ||
| </DESCRIPTION> | ||
| <!-- VOTable description at http://www.ivoa.net/Documents/latest/VOT.html --> | ||
| <INFO name="service_protocol" value="ASU"> IVOID of the protocol through which the data was retrieved</INFO> | ||
| <INFO name="request_date" value="2024-03-21T15:16:08"> Query execution date</INFO> | ||
| <INFO name="request" | ||
| value="https://vizier.cds.unistra.fr/viz-bin/votable?-oc.form=dec&-out.max=5&-out.add=_r&-out.add=_RAJ,_DEJ&-sort=_r&-c.eq=J2000&-c.r= 2&-c.u=arcmin&-c.geom=r&-source=I/355/gaiadr3&-order=I&-out.orig=standard&-out=DR3Name&-out=RA_ICRS&-out=DE_ICRS&-out=Source&-out=e_RA_ICRS&-out=e_DE_ICRS&-out=Plx&-out=e_Plx&-out=PM&-out=pmRA&-out=e_pmRA&-out=pmDE&-out=e_pmDE&-out=RADEcor&-out=RAPlxcor&-out=RApmRAcor&-out=RApmDEcor&-out=DEPlxcor&-out=DEpmRAcor&-out=DEpmDEcor&-out=PlxpmRAcor&-out=PlxpmDEcor&-out=pmRApmDEcor&-out=RV&-out=e_RV&-out=Vbroad&-out=GRVSmag&-out=QSO&-out=Gal&-out=NSS&-out=XPcont&-out=XPsamp&-out=RVS&-out=EpochPh&-out=EpochRV&-out=MCMCGSP&-out=MCMCMSC&-out=And&-out=Teff&-out=logg&-out=[Fe/H]&-out=Dist&-out=A0&-out=HIP&-out=PS1&-out=SDSS13&-out=SKYM2&-out=TYC2&-out=URAT1&-out=AllWISE&-out=APASS9&-out=GSC23&-out=RAVE5&-out=2MASS&-out=RAVE6&-out=RAJ2000&-out=DEJ2000&"> Full request URL (POST)</INFO> | ||
| <INFO name="contact" value="cds-question@unistra.fr"> Email or URL to contact publisher</INFO> | ||
| <INFO name="server_software" value="7.33.3"> Software version</INFO> | ||
| <INFO name="publisher" value="CDS"> Data centre that produced the VOTable</INFO> | ||
| <!-- Execution Reports --> | ||
| <RESOURCE ID="yCat_1355" name="I/355"> | ||
| <DESCRIPTION>Gaia DR3 Part 1. Main source (Gaia Collaboration, 2022)</DESCRIPTION> | ||
| <INFO name="ivoid" value="ivo://cds.vizier/i/355"> IVOID of underlying data collection </INFO> | ||
| <INFO name="creator" value="Gaia collaboration"> First author or institution </INFO> | ||
| <INFO name="cites" value="bibcode:2022yCat.1355....0G"> Bibcode of the dataset </INFO> | ||
| <INFO name="original_date" value="2022"> Year of the article publication </INFO> | ||
| <INFO name="reference_url" value="https://cdsarc.cds.unistra.fr/viz-bin/cat/I/355"> Dataset landing page </INFO> | ||
| <INFO name="citation" value="doi:10.26093/cds/vizier.1355"> Dataset identifier that can be used for citation </INFO> | ||
| <INFO name="publication_date" value="2024-01-24"> Date of first publication in the data centre </INFO> | ||
| <INFO name="rights_uri" value="https://cds.unistra.fr/vizier-org/licences_vizier.html"> Licence URI </INFO> | ||
| <COOSYS ID="H_2016.000" system="ICRS" epoch="2016.000" /> | ||
| <COOSYS ID="J2000" system="eq_FK5" equinox="J2000" /> | ||
| <RESOURCE type="meta"> | ||
| <VODML xmlns="http://www.ivoa.net/xml/mivot"> | ||
| <REPORT status="OK">hand-made mapping</REPORT> | ||
| <MODEL name="ivoa" url="https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml" /> | ||
| <MODEL name="coords" url="https://www.ivoa.net/xml/STC/20200908/Coords-v1.0.vo-dml.xml" /> | ||
| <MODEL name="meas" url="https://www.ivoa.net/xml/Meas/20200908/Meas-v1.0.vo-dml.xml" /> | ||
| <MODEL name="mango" url="https://raw.githubusercontent.com/lmichel/MANGO/draft-0.1/vo-dml/mango.vo-dml.xml" /> | ||
| <GLOBALS> | ||
| <INSTANCE dmid="_spacesys_icrs" dmrole="" dmtype="coords:SpaceSys"> | ||
| <INSTANCE dmrole="coords:PhysicalCoordSys.frame" dmtype="coords:SpaceFrame"> | ||
| <ATTRIBUTE dmrole="coords:SpaceFrame.spaceRefFrame" dmtype="ivoa:string" value="ICRS" /> | ||
| <INSTANCE dmrole="coords:SpaceFrame.refPosition" dmtype="coords:StdRefLocation"> | ||
| <ATTRIBUTE dmrole="coords:StdRefLocation.position" dmtype="ivoa:string" value="BARYCENTER"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <!-- Not sure about the time frame used for the GAIA catalog --> | ||
| <INSTANCE dmid="_timesys_tcb" dmrole="" dmtype="coords:TimeSys"> | ||
| <INSTANCE dmrole="coords:PhysicalCoordSys.frame" dmtype="coords:TimeFrame"> | ||
| <ATTRIBUTE dmrole="coords:TimeFrame.timescale" dmtype="ivoa:string" value="TCB" /> | ||
| <INSTANCE dmrole="coords:TimeFrame.refPosition" dmtype="coords:StdRefLocation"> | ||
| <ATTRIBUTE dmrole="coords:StdRefLocation.position" dmtype="ivoa:string" value="BARYCENTER"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </GLOBALS> | ||
| <TEMPLATES> | ||
| <INSTANCE dmtype="mango:EpochPosition"> | ||
| <!-- This class is a view of \texttt{Astronomical Coordinates and Coordinate Systems} components that have been put together | ||
| to form a consistent description of the position of an object moving over time. It consists of a celestial position, a proper motion, | ||
| a radial velocity and a parallax. All components share the same spatial coordinate system. \begin{itemize} \item Both position and | ||
| proper motion reuse the \texttt{coords:LonLatPoint} elements. \item The space coordinate system is imported from \texttt{coords:spaceSys}. | ||
| \end{itemize} The error is specific to this class as it must support covariance and correlation between the components. " --> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.longitude" dmtype="ivoa:RealQuantity" ref="RA_ICRS" unit="deg"/> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.latitude" dmtype="ivoa:RealQuantity" ref="DE_ICRS" unit="deg"/> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.parallax" dmtype="ivoa:RealQuantity" unit="mas" ref="Plx" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.radialVelocity" dmtype="ivoa:RealQuantity" unit="km/s" ref="RV" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.pmLongitude" dmtype="ivoa:RealQuantity" unit="mas/yr" ref="pmRA" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.pmLatitude" dmtype="ivoa:RealQuantity" unit="mas/yr" ref="pmDE" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.epoch" dmtype="coords:Epoch" value="2016.5" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPosition.pmCosLat_applied" dmtype="ivoa:boolean" value="true" /> | ||
| <!-- Errors on individual quantities --> | ||
| <INSTANCE dmrole="mango:EpochPosition.errors" dmtype="mango:EpochPositionErrors"> | ||
| <!-- Error on parallax --> | ||
| <INSTANCE dmrole="mango:EpochPositionErrors.parallax" dmtype="mango:error.PropertyError1D"> | ||
| <ATTRIBUTE dmrole="mango:error.PropertyError1D.sigma" dmtype="ivoa:RealQuantity" unit="mas" ref="e_Plx" /> | ||
| </INSTANCE> | ||
| <!-- Error on radial velocity --> | ||
| <INSTANCE dmrole="mango:EpochPositionErrors.radialVelocity" dmtype="mango:error.PropertyError1D"> | ||
| <ATTRIBUTE dmrole="mango:error.PropertyError1D.sigma" dmtype="ivoa:RealQuantity" unit="km/s" ref="e_RV" /> | ||
| </INSTANCE> | ||
| <!-- Error on position (diagonal matrix) --> | ||
| <INSTANCE dmrole="mango:EpochPositionErrors.position" dmtype="mango:error.ErrorCorrMatrix"> | ||
| <!-- Error matrix for 2D quantities" --> | ||
| <ATTRIBUTE dmrole="mango:error.ErrorCorrMatrix.sigma1" dmtype="ivoa:RealQuantity" unit="mas" ref="e_RA_ICRS" /> | ||
| <ATTRIBUTE dmrole="mango:error.ErrorCorrMatrix.sigma2" dmtype="ivoa:RealQuantity" unit="mas" ref="e_DE_ICRS" /> | ||
| </INSTANCE> | ||
| <!-- Error on proper motion (diagonal matrix) --> | ||
| <INSTANCE dmrole="mango:EpochPositionErrors.properMotion" dmtype="mango:error.ErrorCorrMatrix"> | ||
| <!-- Error matrix for 2D quantities" --> | ||
| <ATTRIBUTE dmrole="mango:error.ErrorCorrMatrix.sigma1" dmtype="ivoa:RealQuantity" unit="mas/yr" ref="e_pmRA" /> | ||
| <ATTRIBUTE dmrole="mango:error.ErrorCorrMatrix.sigma2" dmtype="ivoa:RealQuantity" unit="mas/yr" ref="e_pmDE" /> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <!-- Correlation between quantities --> | ||
| <INSTANCE dmrole="mango:EpochPosition.correlations" dmtype="mango:EpochPositionCorrelations"> | ||
| <!-- Position/proper-motion correlation --> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.isCovariance" dmtype="ivoa:boolean" value="false" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.latitudePmLongitude" dmtype="ivoa:real" ref="DEpmRAcor" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.latitudePmLatitude" dmtype="ivoa:real" ref="DEpmDEcor" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.longitudePmLongitude" dmtype="ivoa:real" ref="RApmRAcor" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.longitudePmLatitude" dmtype="ivoa:real" ref="RApmDEcor" /> | ||
| <!-- parallax/proper-motion correlation --> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.pmLongitudeParallax" dmtype="ivoa:real" ref="PlxpmRAcor" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.pmLatitudeParallax" dmtype="ivoa:real" ref="PlxpmDEcor" /> | ||
| <!-- position/parallax correlation --> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.longitudeParallax" dmtype="ivoa:real" ref="RAPlxcor" /> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.latitudeParallax" dmtype="ivoa:real" ref="DEPlxcor" /> | ||
| <!-- position/position correlation --> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.longitudeLatitude" dmtype="ivoa:real" ref="RADEcor" /> | ||
| <!-- proper-motion/proper-motion correlation --> | ||
| <ATTRIBUTE dmrole="mango:EpochPositionCorrelations.pmLongitudePmLatitude" dmtype="ivoa:real" ref="pmRApmDEcor" /> | ||
| </INSTANCE> | ||
| <REFERENCE dmref="_spacesys_icrs" dmrole="mango:EpochPosition.spaceSys" /> | ||
| <REFERENCE dmref="_timesys_tcb" dmrole="mango:EpochPosition.timeSys" /> | ||
| </INSTANCE> | ||
| </TEMPLATES> | ||
| </VODML> | ||
| </RESOURCE> | ||
| <TABLE ID="I_355_gaiadr3" name="I/355/gaiadr3"> | ||
| <DESCRIPTION>Gaia DR3 source catalog (1811709771 sources)</DESCRIPTION> | ||
| <!-- Gaia data release 3 (Gaia DR3). (\originalcolumnnames)\vizContent{timeSerie}\vizContent{spectrum} --> | ||
| <!-- Definitions of GROUPs and FIELDs --> | ||
| <FIELD name="_RAJ2000" ucd="pos.eq.ra" ref="J2000" datatype="double" width="17" precision="13" unit="deg"><!-- ucd="POS_EQ_RA" --> | ||
| <DESCRIPTION>Right ascension (FK5, Equinox=J2000.0) at Epoch=J2000, proper motions taken into account </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="_DEJ2000" ucd="pos.eq.dec" ref="J2000" datatype="double" width="17" precision="13" unit="deg"><!-- ucd="POS_EQ_DEC" --> | ||
| <DESCRIPTION>Declination (FK5, Equinox=J2000.0) at Epoch=J2000, proper motions taken into account </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DR3Name" ucd="meta.id" datatype="char" arraysize="28*"><!-- ucd="ID_ALTERNATIVE" --> | ||
| <DESCRIPTION>Unique source designation (unique across all Data Releases) (designation)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RA_ICRS" ucd="pos.eq.ra;meta.main" ref="H_2016.000" datatype="double" width="15" precision="11" | ||
| unit="deg"><!-- ucd="POS_EQ_RA_MAIN" --> | ||
| <DESCRIPTION>Right ascension (ICRS) at Ep=2016.0 (ra)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DE_ICRS" ucd="pos.eq.dec;meta.main" ref="H_2016.000" datatype="double" width="15" precision="11" | ||
| unit="deg"><!-- ucd="POS_EQ_DEC_MAIN" --> | ||
| <DESCRIPTION>Declination (ICRS) at Ep=2016.0 (dec)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="Source" ucd="meta.id;meta.main" datatype="long" width="19"><!-- ucd="ID_MAIN" --> | ||
| <DESCRIPTION>Unique source identifier (unique within a particular Data Release) (source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="e_RA_ICRS" ucd="stat.error;pos.eq.ra" datatype="double" width="7" precision="4" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>Standard error of right ascension (ra_error)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="e_DE_ICRS" ucd="stat.error;pos.eq.dec" datatype="double" width="7" precision="4" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>Standard error of declination (dec_error)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="Plx" ucd="pos.parallax.trig" datatype="double" width="9" precision="4" unit="mas"><!-- ucd="POS_PARLX_TRIG" --> | ||
| <DESCRIPTION>? Parallax (parallax)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Plx" ucd="stat.error;pos.parallax.trig" datatype="float" width="7" precision="4" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Standard error of parallax (parallax_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="PM" ucd="pos.pm;pos.eq" datatype="double" width="9" precision="3" unit="mas/yr"><!-- ucd="POS_EQ_PM" --> | ||
| <DESCRIPTION>? Total proper motion (pm)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmRA" ucd="pos.pm;pos.eq.ra" ref="H_2016.000" datatype="double" width="9" precision="3" unit="mas/yr"><!-- ucd="POS_EQ_PMRA" --> | ||
| <DESCRIPTION>? Proper motion in right ascension direction, pmRA*cosDE (pmra)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_pmRA" ucd="stat.error;pos.pm;pos.eq.ra" datatype="float" width="6" precision="3" unit="mas/yr"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Standard error of proper motion in right ascension direction (pmra_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmDE" ucd="pos.pm;pos.eq.dec" ref="H_2016.000" datatype="double" width="9" precision="3" unit="mas/yr"><!-- ucd="POS_EQ_PMDEC" --> | ||
| <DESCRIPTION>? Proper motion in declination direction (pmdec)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_pmDE" ucd="stat.error;pos.pm;pos.eq.dec" datatype="float" width="6" precision="3" unit="mas/yr"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Standard error of proper motion in declination direction (pmdec_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RADEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1] Correlation between right ascension and declination (ra_dec_corr)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAPlxcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between right ascension and parallax (ra_parallax_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RApmRAcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between right ascension and proper motion in right ascension (ra_pmra_corr) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RApmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between right ascension and proper motion in declination (ra_pmdec_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="DEPlxcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between declination and parallax (dec_parallax_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="DEpmRAcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between declination and proper motion in right ascension (dec_pmra_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="DEpmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between declination and proper motion in declination (dec_pmdec_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="PlxpmRAcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between parallax and proper motion in right ascension (parallax_pmra_corr) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="PlxpmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between parallax and proper motion in declination (parallax_pmdec_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmRApmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between proper motion in right ascension and proper motion in declination | ||
| (pmra_pmdec_corr) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RV" ucd="spect.dopplerVeloc.opt;em.opt.I" datatype="double" width="7" precision="2" unit="km/s"><!-- ucd="VELOC_BARYCENTER" --> | ||
| <DESCRIPTION>? Radial velocity (radial_velocity)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_RV" ucd="stat.error;spect.dopplerVeloc.opt;em.opt.I" datatype="float" width="5" precision="2" | ||
| unit="km/s"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Radial velocity error (radial_velocity_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="Vbroad" ucd="spect.dopplerVeloc.opt;em.opt.I" datatype="double" width="8" precision="4" unit="km/s"><!-- ucd="SPECT_LINE_BROADENING" --> | ||
| <DESCRIPTION>? Spectral line broadening parameter (vbroad)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="GRVSmag" ucd="phot.mag;em.opt" datatype="double" width="9" precision="6" unit="mag"><!-- ucd="PHOT_MAG_OPTICAL" --> | ||
| <DESCRIPTION>? Integrated Grvs magnitude (grvs_mag)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="QSO" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of additional information in the QSO candidates table | ||
| (in_qso_candidates) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${QSO}%7d%5cvMore%7b-source=I/356/qsocand%5c%26Source=${Source}%7d%7b${QSO}%7d%5celse%7b${QSO}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="Gal" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of additional information in the galaxy candidates table | ||
| (in_galaxy_candidates) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${Gal}%7d%5cvMore%7b-source=I/356/galcand%5c%26Source=${Source}%7d%7b${Gal}%7d%5celse%7b${Gal}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="NSS" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/7] Flag indicating the availability of additional information in the various Non-Single Star tables | ||
| (non_single_star) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${NSS}%7d%5cvMore%7b-source=I/357/tb%2a%5c%26Source=${Source}%7d%7b${NSS}%7d%5celse%7b${NSS}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="XPcont" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of mean BP/RP spectrum in continuous representation for this source | ||
| (has_xp_continuous) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${XPcont}%7d%5cvMore%7b-source=I/355/xpco%2a%5c%26Source=${Source}%7d%7b${XPcont}%7d%5celse%7b${XPcont}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="XPsamp" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of mean BP/RP spectrum in sampled form for this source | ||
| (has_xp_sampled) | ||
| </DESCRIPTION> | ||
| <LINK content-type="timeserie/votable" | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${XPsamp}%7d%5cvizContent%7bspectrum%7d%5cvplotTS%7bI/355%7d%7b.graph_sql_xpsamp%7d%7bPos=${RA_ICRS}${DE_ICRS}%26Source=${Source}%7d%7b${XPsamp}%7d%5celse%7b${XPsamp}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="RVS" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of mean RVS spectrum for this source (has_rvs)</DESCRIPTION> | ||
| <LINK content-type="timeserie/votable" | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${RVS}%7d%5cvizContent%7btimeSerie%7d%5cvplotTS%7bI/355%7d%7b.graph_sql_rvs%7d%7bPos=${RA_ICRS}${DE_ICRS}%26Source=${Source}%7d%7b${RVS}%7d%5celse%7b${RVS}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="EpochPh" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of epoch photometry for this source (has_epoch_photometry) | ||
| </DESCRIPTION> | ||
| <LINK content-type="timeserie/votable" | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${EpochPh}%7d%5cvizContent%7btimeSerie%7d%5cvplotTS%7bI/355%7d%7b.graph_sql_epphot%7d%7bPos=${RA_ICRS}${DE_ICRS}%26Source=${Source}%7d%7b${EpochPh}%7d%5celse%7b${EpochPh}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="EpochRV" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of epoch radial velocity for this source (has_epoch_rv) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${EpochRV}%7d%5cvMore%7b-source=I/358/veprv%5c%26Source=${Source}%7d%7b${EpochRV}%7d%5celse%7b${EpochRV}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="MCMCGSP" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of GSP-Phot MCMC samples for this source (has_mcmc_gspphot) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="MCMCMSC" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of MSC MCMC samples for this source (has_mcmc_msc)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="And" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating that the source is present in the Gaia Andromeda Photometric Survey (GAPS) | ||
| (in_andromeda_survey) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="Teff" ucd="phys.temperature.effective" datatype="double" width="7" precision="1" unit="K"><!-- ucd="PHYS_TEMP_EFFEC" --> | ||
| <DESCRIPTION>? Effective temperature from GSP-Phot Aeneas best library using BP/RP spectra (teff_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="logg" ucd="phys.gravity" datatype="double" width="7" precision="4" unit="log(cm.s**-2)"><!-- ucd="PHYS_GRAVITY_SURFACE" --> | ||
| <DESCRIPTION>? Surface gravity from GSP-Phot Aeneas best library using BP/RP spectra (logg_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="[Fe/H]" ID="__Fe_H_" ucd="phys.abund.Z" datatype="double" width="7" precision="4" unit=""><!-- ucd="PHYS_ABUND_FE/H" --> | ||
| <DESCRIPTION>? Iron abundance from GSP-Phot Aeneas best library using BP/RP spectra (mh_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="Dist" ucd="pos.distance;pos.eq" datatype="double" width="10" precision="4" unit="pc"><!-- ucd="PHYS_DISTANCE_TRUE" --> | ||
| <DESCRIPTION>? Distance from GSP-Phot Aeneas best library using BP/RP spectra (distance_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="A0" ucd="phys.absorption;em.opt" datatype="double" width="7" precision="4" unit="mag"><!-- ucd="PHOT_EXTINCTION_TOTAL" --> | ||
| <DESCRIPTION>? Monochromatic extinction A_0 at 547.7nm from GSP-Phot Aeneas best library using BP/RP spectra | ||
| (azero_gspphot) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="HIP" ucd="meta.number;phys.atmol.number" datatype="int" width="6"><!-- ucd="ID_NUMBER" --> | ||
| <DESCRIPTION>? HIP cross-id number, van Leeuwen, Cat. I/311 (hip_original_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-2147483648" /> | ||
| </FIELD> | ||
| <FIELD name="PS1" ucd="meta.id.cross" datatype="long" width="18"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? PS1 cross-id name, Chambers et al., Cat. II/349 (ps1_original_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-9223372036854775808" /> | ||
| </FIELD> | ||
| <FIELD name="SDSS13" ucd="meta.id.cross" datatype="long" width="19"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? SDSS name, Albareti et al., 2017ApJS..233...25A (sdss13_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-9223372036854775808" /> | ||
| </FIELD> | ||
| <FIELD name="SKYM2" ucd="meta.id.cross" datatype="int" width="9"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? SkyMapperDR2 cross-id name, Onken et al., 2019PASA...36...33O (skym2_original_ext_source_id) | ||
| </DESCRIPTION> | ||
| <VALUES null="-2147483648" /> | ||
| </FIELD> | ||
| <FIELD name="TYC2" ucd="meta.id.cross" datatype="char" arraysize="12*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>Tycho-2 cross-id name, Hog et al., Cat. I/259 (tyc2_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="URAT1" ucd="meta.id.cross" datatype="char" arraysize="15*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>URAT1 name, Zacharias et al., Cat. I/329 (urat1_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="AllWISE" ucd="meta.id.cross" datatype="char" arraysize="19*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>ALLWISE cross-id name, Cutri et al., Cat. II/328 (allwise_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="APASS9" ucd="meta.id.cross" datatype="int" width="8"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? APASS9 identification, Henden et al., Cat. II/336 (apass9_original_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-2147483648" /> | ||
| </FIELD> | ||
| <FIELD name="GSC23" ucd="meta.id.cross" datatype="char" arraysize="10*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>GSC2.3 cross-id name, Lasker et al., Cat. I/305 (gsc23_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAVE5" ucd="meta.id.cross" datatype="char" arraysize="16*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>RAVE DR5 cross-id name, Kunder et al., Cat. III/279 (rave5_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="2MASS" ucd="meta.id.cross" ID="_2MASS" datatype="char" arraysize="17*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>2MASS cross-id name, Cutri et al., Cat. II/246 (twomass_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAVE6" ucd="meta.id.cross" datatype="char" arraysize="21*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>RAVE DR6 cross-id name, Steinmetz et al., Cat. III/283 (rave6_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAJ2000" ucd="pos.eq.ra" datatype="double" width="15" precision="11" unit="deg"><!-- ucd="POS_EQ_RA_OTHER" --> | ||
| <DESCRIPTION>Barycentric right ascension (ICRS) at Ep=2000.0 (added by CDS) (ra2000)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DEJ2000" ucd="pos.eq.dec" datatype="double" width="15" precision="11" unit="deg"><!-- ucd="POS_EQ_DEC_OTHER" --> | ||
| <DESCRIPTION>Barycentric declination (ICRS) at Ep=2000.0 (added by CDS) (dec2000)</DESCRIPTION> | ||
| </FIELD> | ||
| <DATA> | ||
| <TABLEDATA> | ||
| <TR> | ||
| <TD>307.7911702004070</TD> | ||
| <TD>+20.4311044212247</TD> | ||
| <TD>Gaia DR3 1816065554621487360</TD> | ||
| <TD>307.79115807079</TD> | ||
| <TD>+20.43108005561</TD> | ||
| <TD>1816065554621487360</TD> | ||
| <TD>0.0511</TD> | ||
| <TD>0.0477</TD> | ||
| <TD>0.4319</TD> | ||
| <TD>0.0691</TD> | ||
| <TD>6.049</TD> | ||
| <TD>-2.557</TD> | ||
| <TD>0.064</TD> | ||
| <TD>-5.482</TD> | ||
| <TD>0.067</TD> | ||
| <TD>0.1212</TD> | ||
| <TD>0.1337</TD> | ||
| <TD>-0.4109</TD> | ||
| <TD>-0.0072</TD> | ||
| <TD>0.0069</TD> | ||
| <TD>-0.0085</TD> | ||
| <TD>-0.2983</TD> | ||
| <TD>-0.2603</TD> | ||
| <TD>-0.0251</TD> | ||
| <TD>0.2688</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>1</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>1</TD> | ||
| <TD>1</TD> | ||
| <TD>0</TD> | ||
| <TD>4696.2</TD> | ||
| <TD>4.1928</TD> | ||
| <TD>-0.7942</TD> | ||
| <TD>2428.5532</TD> | ||
| <TD>0.0380</TD> | ||
| <TD></TD> | ||
| <TD>132513077911637877</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>URAT1-553569515</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD017546</TD> | ||
| <TD></TD> | ||
| <TD>20310987+2025519</TD> | ||
| <TD></TD> | ||
| <TD>307.79117020041</TD> | ||
| <TD>20.43110442122</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7958370989668</TD> | ||
| <TD>+20.4325479549513</TD> | ||
| <TD>Gaia DR3 1816065558924798592</TD> | ||
| <TD>307.79582391363</TD> | ||
| <TD>+20.43253083107</TD> | ||
| <TD>1816065558924798592</TD> | ||
| <TD>0.3203</TD> | ||
| <TD>0.2898</TD> | ||
| <TD>-0.5553</TD> | ||
| <TD>0.4195</TD> | ||
| <TD>4.751</TD> | ||
| <TD>-2.780</TD> | ||
| <TD>0.395</TD> | ||
| <TD>-3.853</TD> | ||
| <TD>0.426</TD> | ||
| <TD>0.3740</TD> | ||
| <TD>0.1981</TD> | ||
| <TD>-0.3253</TD> | ||
| <TD>-0.0486</TD> | ||
| <TD>0.0632</TD> | ||
| <TD>-0.0608</TD> | ||
| <TD>-0.1303</TD> | ||
| <TD>-0.2989</TD> | ||
| <TD>-0.0876</TD> | ||
| <TD>0.4716</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>132513077957999584</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD017483</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.79583709897</TD> | ||
| <TD>20.43254795495</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7973736604703</TD> | ||
| <TD>+20.4355882715396</TD> | ||
| <TD>Gaia DR3 1816065558920966528</TD> | ||
| <TD>307.79737366047</TD> | ||
| <TD>+20.43558827154</TD> | ||
| <TD>1816065558920966528</TD> | ||
| <TD>6.0643</TD> | ||
| <TD>2.1063</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0.7514</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>132523077973693273</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.79737366047</TD> | ||
| <TD>20.43558827154</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7885745651585</TD> | ||
| <TD>+20.4301331822264</TD> | ||
| <TD>Gaia DR3 1816065558924801792</TD> | ||
| <TD>307.78856137441</TD> | ||
| <TD>+20.43011713943</TD> | ||
| <TD>1816065558924801792</TD> | ||
| <TD>0.1196</TD> | ||
| <TD>0.1127</TD> | ||
| <TD>0.0910</TD> | ||
| <TD>0.1671</TD> | ||
| <TD>4.557</TD> | ||
| <TD>-2.781</TD> | ||
| <TD>0.153</TD> | ||
| <TD>-3.610</TD> | ||
| <TD>0.165</TD> | ||
| <TD>0.1448</TD> | ||
| <TD>0.1580</TD> | ||
| <TD>-0.3400</TD> | ||
| <TD>0.0468</TD> | ||
| <TD>0.0149</TD> | ||
| <TD>0.0299</TD> | ||
| <TD>-0.2083</TD> | ||
| <TD>-0.2178</TD> | ||
| <TD>0.0615</TD> | ||
| <TD>0.3266</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>1</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>5071.5</TD> | ||
| <TD>4.6975</TD> | ||
| <TD>-0.7109</TD> | ||
| <TD>2923.6248</TD> | ||
| <TD>0.0090</TD> | ||
| <TD></TD> | ||
| <TD>132513077885716709</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>URAT1-553569502</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD017266</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.78857456516</TD> | ||
| <TD>20.43013318223</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7897816527446</TD> | ||
| <TD>+20.4315208963567</TD> | ||
| <TD>Gaia DR3 1816065554622254464</TD> | ||
| <TD>307.78977228741</TD> | ||
| <TD>+20.43150439876</TD> | ||
| <TD>1816065554622254464</TD> | ||
| <TD>0.3688</TD> | ||
| <TD>0.3801</TD> | ||
| <TD>-0.6243</TD> | ||
| <TD>0.5059</TD> | ||
| <TD>4.205</TD> | ||
| <TD>-1.975</TD> | ||
| <TD>0.444</TD> | ||
| <TD>-3.712</TD> | ||
| <TD>0.498</TD> | ||
| <TD>0.2553</TD> | ||
| <TD>0.0889</TD> | ||
| <TD>-0.3890</TD> | ||
| <TD>-0.0365</TD> | ||
| <TD>-0.0773</TD> | ||
| <TD>-0.0307</TD> | ||
| <TD>-0.2998</TD> | ||
| <TD>-0.2452</TD> | ||
| <TD>0.0025</TD> | ||
| <TD>0.3249</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>132513077897708356</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD096440</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.78978165274</TD> | ||
| <TD>20.43152089636</TD> | ||
| </TR> | ||
| </TABLEDATA> | ||
| </DATA> | ||
| </TABLE> | ||
| <INFO name="matches" value="5">matching records</INFO> | ||
| <INFO name="Warning" value="No center provided++++" /> | ||
| <INFO name="Warning" value="increase the precision for computed column 14" /> | ||
| <INFO name="Warning" value="increase the precision for computed column 14" /> | ||
| <INFO name="Warning" value="truncated result (maxtup=5)" /> | ||
| <INFO name="QUERY_STATUS" value="OVERFLOW"> value="truncated result (maxtup=5)"</INFO> | ||
| </RESOURCE> | ||
| </VOTABLE> |
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xmlns="http://www.ivoa.net/xml/VOTable/v1.3" | ||
| xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/v1.3"> | ||
| <DESCRIPTION> | ||
| VizieR Astronomical Server cds:8082 | ||
| Date: 2025-04-19T10:08:58 [V7.5] | ||
| Explanations and Statistics of UCDs: See LINK below | ||
| In case of problem, please report to: cds-question@unistra.fr | ||
| </DESCRIPTION> | ||
| <!-- VOTable description at http://www.ivoa.net/Documents/latest/VOT.html --> | ||
| <INFO name="service_protocol" value="ivo://ivoa.net/std/ConeSearch/v1.03"> IVOID of the protocol through which the data was retrieved</INFO> | ||
| <INFO name="request_date" value="2025-04-19T10:08:58"> Query execution date</INFO> | ||
| <INFO name="request" value="https://cds/local/viz-bin/mivotconesearch/VIII/6/maps?RA=0.6405&DEC=-8.221&SR=1"> Full request URL</INFO> | ||
| <INFO name="contact" value="cds-question@unistra.fr"> Email or URL to contact publisher</INFO> | ||
| <INFO name="server_software" value="7.5"> Software version</INFO> | ||
| <INFO name="publisher" value="CDS"> Data centre that produced the VOTable</INFO> | ||
| <!-- | ||
| Execution Reports | ||
| --> | ||
| <INFO name="MaxTuples" value="50000" /> | ||
| <INFO ID="Target" name="-c" value="000.640500-08.221000,rd=1."> | ||
| Constraint -out.meta=dhuM</INFO> | ||
| <RESOURCE ID="yCat_8006" name="VIII/6" type="results"> | ||
| <DESCRIPTION>1400-MHz Sky Survey, Maps Covering Dec -5 to +82 (Condon+ 1985-86)</DESCRIPTION> <INFO name="ivoid" value="ivo://cds.vizier/viii/6"> IVOID of underlying data collection </INFO> | ||
| <INFO name="creator" value="Condon J.J."> First author or institution </INFO> | ||
| <INFO name="cites" value="bibcode:1985AJ.....90.2540C"> Article or Data origin sources </INFO> | ||
| <INFO name="editor" value="Astronomical Journal (AAS)"> Editor name (article) </INFO> | ||
| <INFO name="original_date" value="1985"> Year of the article publication </INFO> | ||
| <INFO name="reference_url" value="https://cdsarc.cds.unistra.fr/viz-bin/cat/VIII/6"> Dataset landing page </INFO> | ||
| <INFO name="publication_date" value="2018-01-31"> Date of first publication in the data centre </INFO> | ||
| <INFO name="rights_uri" value="https://cds.unistra.fr/vizier-org/licences_vizier.html"> Licence URI </INFO> | ||
| <COOSYS ID="B1950" system="eq_FK4" equinox="B1950"/> | ||
| <TABLE ID="VIII_6_maps" name="VIII/6/maps"> | ||
| <DESCRIPTION>List of the map centers</DESCRIPTION> | ||
| <!-- Definitions of GROUPs and FIELDs --> | ||
| <!--The precision of the computed positions has been increased compared to the original positions--> | ||
| <FIELD name="_r" ucd="pos.angDistance" datatype="double" width="4" precision="2" unit=""><!-- ucd="POS_ANG_DIST_GENERAL" --> | ||
| <DESCRIPTION>Distance from center (000.0-08.5)[FK4/B1950]</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="recno" ucd="ID_MAIN" datatype="char" arraysize="8*"><!-- ucd="meta.record" --> | ||
| <DESCRIPTION>Record number assigned by the VizieR team. Should Not be used for identification. [datatype=int]</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="ObsDate" ucd="time.epoch;obs" datatype="char" arraysize="10" unit="'Y:M:D'"><!-- ucd="TIME_DATE" --> | ||
| <DESCRIPTION>Observation date</DESCRIPTION> | ||
| <VALUES null=" " /> | ||
| </FIELD> | ||
| <FIELD name="RAB1950" ucd="POS_EQ_RA_MAIN" ref="B1950" datatype="double" width="5" precision="1" unit="deg"><!-- ucd="pos.eq.ra;meta.main" --> | ||
| <DESCRIPTION>Right Ascension (B1950) of map center</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DEB1950" ucd="POS_EQ_DEC_MAIN" ref="B1950" datatype="double" width="5" precision="1" unit="deg"><!-- ucd="pos.eq.dec;meta.main" --> | ||
| <DESCRIPTION>Declination (B1950) of map center</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="FITSfile" ucd="meta.id;meta.fits" datatype="char" arraysize="8"><!-- ucd="ID_FILE" --> | ||
| <DESCRIPTION>Name of FITS file in "maps" subdirectory</DESCRIPTION> | ||
| <!-- Name of FITS file in "\begin{tex}\vFile{VIII/6/./maps}{maps}\end{tex}" subdirectory --> | ||
| </FIELD> | ||
| <FIELD name="AssocData" ucd="meta.bib.page" datatype="char" arraysize="4"><!-- ucd="DATA_LINK" --> | ||
| <DESCRIPTION>Associated Data web page</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="FITS" ucd="meta.ref.url" datatype="char" arraysize="4"><!-- ucd="DATA_LINK" --> | ||
| <DESCRIPTION>Downbload the FITS file</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="_RA.icrs" ucd="pos.eq.ra" datatype="double" width="8" precision="4" unit="deg"><!-- ucd="POS_EQ_RA_OTHER" --> | ||
| <DESCRIPTION>Right ascension (ICRS) (computed by VizieR, not part of the original data)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="_DE.icrs" ucd="pos.eq.dec" datatype="double" width="8" precision="4" unit="deg"><!-- ucd="POS_EQ_DEC_OTHER" --> | ||
| <DESCRIPTION>Declination (ICRS) (computed by VizieR, not part of the original data)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <DATA><TABLEDATA> | ||
| <TR><TD>0.00</TD><TD>1</TD><TD>1983-10-06</TD><TD>000.0</TD><TD>-08.5</TD><TD>f001.fit</TD><TD>fits</TD><TD>FITS</TD><TD>000.6405</TD><TD>-08.2216</TD></TR> | ||
| </TABLEDATA></DATA> | ||
| </TABLE> | ||
| <INFO name="matches" value="1">matching records</INFO> | ||
| </RESOURCE> | ||
| </VOTABLE> |
Sorry, the diff of this file is too big to display
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xmlns="http://www.ivoa.net/xml/VOTable/v1.3" | ||
| xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/v1.3"> | ||
| <DESCRIPTION> | ||
| VizieR Astronomical Server vizier.cds.unistra.fr | ||
| Date: 2024-03-21T15:16:08 [V7.33.3] | ||
| Explanations and Statistics of | ||
| UCDs: See LINK below | ||
| In case of problem, please report to: cds-question@unistra.fr | ||
| </DESCRIPTION> | ||
| <!-- VOTable description at http://www.ivoa.net/Documents/latest/VOT.html --> | ||
| <INFO name="service_protocol" value="ASU"> IVOID of the protocol through which the data was retrieved</INFO> | ||
| <INFO name="request_date" value="2024-03-21T15:16:08"> Query execution date</INFO> | ||
| <INFO name="request" | ||
| value="https://vizier.cds.unistra.fr/viz-bin/votable?-oc.form=dec&-out.max=5&-out.add=_r&-out.add=_RAJ,_DEJ&-sort=_r&-c.eq=J2000&-c.r= 2&-c.u=arcmin&-c.geom=r&-source=I/355/gaiadr3&-order=I&-out.orig=standard&-out=DR3Name&-out=RA_ICRS&-out=DE_ICRS&-out=Source&-out=e_RA_ICRS&-out=e_DE_ICRS&-out=Plx&-out=e_Plx&-out=PM&-out=pmRA&-out=e_pmRA&-out=pmDE&-out=e_pmDE&-out=RADEcor&-out=RAPlxcor&-out=RApmRAcor&-out=RApmDEcor&-out=DEPlxcor&-out=DEpmRAcor&-out=DEpmDEcor&-out=PlxpmRAcor&-out=PlxpmDEcor&-out=pmRApmDEcor&-out=RV&-out=e_RV&-out=Vbroad&-out=GRVSmag&-out=QSO&-out=Gal&-out=NSS&-out=XPcont&-out=XPsamp&-out=RVS&-out=EpochPh&-out=EpochRV&-out=MCMCGSP&-out=MCMCMSC&-out=And&-out=Teff&-out=logg&-out=[Fe/H]&-out=Dist&-out=A0&-out=HIP&-out=PS1&-out=SDSS13&-out=SKYM2&-out=TYC2&-out=URAT1&-out=AllWISE&-out=APASS9&-out=GSC23&-out=RAVE5&-out=2MASS&-out=RAVE6&-out=RAJ2000&-out=DEJ2000&"> Full request URL (POST)</INFO> | ||
| <INFO name="contact" value="cds-question@unistra.fr"> Email or URL to contact publisher</INFO> | ||
| <INFO name="server_software" value="7.33.3"> Software version</INFO> | ||
| <INFO name="publisher" value="CDS"> Data centre that produced the VOTable</INFO> | ||
| <!-- Execution Reports --> | ||
| <RESOURCE ID="yCat_1355" name="I/355"> | ||
| <DESCRIPTION>Gaia DR3 Part 1. Main source (Gaia Collaboration, 2022)</DESCRIPTION> | ||
| <INFO name="ivoid" value="ivo://cds.vizier/i/355"> IVOID of underlying data collection </INFO> | ||
| <INFO name="creator" value="Gaia collaboration"> First author or institution </INFO> | ||
| <INFO name="cites" value="bibcode:2022yCat.1355....0G"> Bibcode of the dataset </INFO> | ||
| <INFO name="original_date" value="2022"> Year of the article publication </INFO> | ||
| <INFO name="reference_url" value="https://cdsarc.cds.unistra.fr/viz-bin/cat/I/355"> Dataset landing page </INFO> | ||
| <INFO name="citation" value="doi:10.26093/cds/vizier.1355"> Dataset identifier that can be used for citation </INFO> | ||
| <INFO name="publication_date" value="2024-01-24"> Date of first publication in the data centre </INFO> | ||
| <INFO name="rights_uri" value="https://cds.unistra.fr/vizier-org/licences_vizier.html"> Licence URI </INFO> | ||
| <COOSYS ID="H_2016.000" system="ICRS" epoch="2016.000" /> | ||
| <COOSYS ID="J2000" system="eq_FK5" equinox="J2000" /> | ||
| <TABLE ID="I_355_gaiadr3" name="I/355/gaiadr3"> | ||
| <DESCRIPTION>Gaia DR3 source catalog (1811709771 sources)</DESCRIPTION> | ||
| <!-- Gaia data release 3 (Gaia DR3). (\originalcolumnnames)\vizContent{timeSerie}\vizContent{spectrum} --> | ||
| <!-- Definitions of GROUPs and FIELDs --> | ||
| <FIELD name="_RAJ2000" ucd="pos.eq.ra" ref="J2000" datatype="double" width="17" precision="13" unit="deg"><!-- ucd="POS_EQ_RA" --> | ||
| <DESCRIPTION>Right ascension (FK5, Equinox=J2000.0) at Epoch=J2000, proper motions taken into account </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="_DEJ2000" ucd="pos.eq.dec" ref="J2000" datatype="double" width="17" precision="13" unit="deg"><!-- ucd="POS_EQ_DEC" --> | ||
| <DESCRIPTION>Declination (FK5, Equinox=J2000.0) at Epoch=J2000, proper motions taken into account </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DR3Name" ucd="meta.id" datatype="char" arraysize="28*"><!-- ucd="ID_ALTERNATIVE" --> | ||
| <DESCRIPTION>Unique source designation (unique across all Data Releases) (designation)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RA_ICRS" ucd="pos.eq.ra;meta.main" ref="H_2016.000" datatype="double" width="15" precision="11" | ||
| unit="deg"><!-- ucd="POS_EQ_RA_MAIN" --> | ||
| <DESCRIPTION>Right ascension (ICRS) at Ep=2016.0 (ra)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DE_ICRS" ucd="pos.eq.dec;meta.main" ref="H_2016.000" datatype="double" width="15" precision="11" | ||
| unit="deg"><!-- ucd="POS_EQ_DEC_MAIN" --> | ||
| <DESCRIPTION>Declination (ICRS) at Ep=2016.0 (dec)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="Source" ucd="meta.id;meta.main" datatype="long" width="19"><!-- ucd="ID_MAIN" --> | ||
| <DESCRIPTION>Unique source identifier (unique within a particular Data Release) (source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="e_RA_ICRS" ucd="stat.error;pos.eq.ra" datatype="double" width="7" precision="4" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>Standard error of right ascension (ra_error)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="e_DE_ICRS" ucd="stat.error;pos.eq.dec" datatype="double" width="7" precision="4" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>Standard error of declination (dec_error)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="Plx" ucd="pos.parallax.trig" datatype="double" width="9" precision="4" unit="mas"><!-- ucd="POS_PARLX_TRIG" --> | ||
| <DESCRIPTION>? Parallax (parallax)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Plx" ucd="stat.error;pos.parallax.trig" datatype="float" width="7" precision="4" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Standard error of parallax (parallax_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="PM" ucd="pos.pm;pos.eq" datatype="double" width="9" precision="3" unit="mas/yr"><!-- ucd="POS_EQ_PM" --> | ||
| <DESCRIPTION>? Total proper motion (pm)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmRA" ucd="pos.pm;pos.eq.ra" ref="H_2016.000" datatype="double" width="9" precision="3" unit="mas/yr"><!-- ucd="POS_EQ_PMRA" --> | ||
| <DESCRIPTION>? Proper motion in right ascension direction, pmRA*cosDE (pmra)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_pmRA" ucd="stat.error;pos.pm;pos.eq.ra" datatype="float" width="6" precision="3" unit="mas/yr"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Standard error of proper motion in right ascension direction (pmra_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmDE" ucd="pos.pm;pos.eq.dec" ref="H_2016.000" datatype="double" width="9" precision="3" unit="mas/yr"><!-- ucd="POS_EQ_PMDEC" --> | ||
| <DESCRIPTION>? Proper motion in declination direction (pmdec)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_pmDE" ucd="stat.error;pos.pm;pos.eq.dec" datatype="float" width="6" precision="3" unit="mas/yr"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Standard error of proper motion in declination direction (pmdec_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RADEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1] Correlation between right ascension and declination (ra_dec_corr)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAPlxcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between right ascension and parallax (ra_parallax_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RApmRAcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between right ascension and proper motion in right ascension (ra_pmra_corr) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RApmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between right ascension and proper motion in declination (ra_pmdec_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="DEPlxcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between declination and parallax (dec_parallax_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="DEpmRAcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between declination and proper motion in right ascension (dec_pmra_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="DEpmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between declination and proper motion in declination (dec_pmdec_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="PlxpmRAcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between parallax and proper motion in right ascension (parallax_pmra_corr) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="PlxpmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between parallax and proper motion in declination (parallax_pmdec_corr)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmRApmDEcor" ucd="stat.correlation" datatype="double" width="7" precision="4"><!-- ucd="STAT_CORRELATION" --> | ||
| <DESCRIPTION>[-1/1]? Correlation between proper motion in right ascension and proper motion in declination | ||
| (pmra_pmdec_corr) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="RV" ucd="spect.dopplerVeloc.opt;em.opt.I" datatype="double" width="7" precision="2" unit="km/s"><!-- ucd="VELOC_BARYCENTER" --> | ||
| <DESCRIPTION>? Radial velocity (radial_velocity)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_RV" ucd="stat.error;spect.dopplerVeloc.opt;em.opt.I" datatype="float" width="5" precision="2" | ||
| unit="km/s"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>? Radial velocity error (radial_velocity_error)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="Vbroad" ucd="spect.dopplerVeloc.opt;em.opt.I" datatype="double" width="8" precision="4" unit="km/s"><!-- ucd="SPECT_LINE_BROADENING" --> | ||
| <DESCRIPTION>? Spectral line broadening parameter (vbroad)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="GRVSmag" ucd="phot.mag;em.opt" datatype="double" width="9" precision="6" unit="mag"><!-- ucd="PHOT_MAG_OPTICAL" --> | ||
| <DESCRIPTION>? Integrated Grvs magnitude (grvs_mag)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="QSO" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of additional information in the QSO candidates table | ||
| (in_qso_candidates) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${QSO}%7d%5cvMore%7b-source=I/356/qsocand%5c%26Source=${Source}%7d%7b${QSO}%7d%5celse%7b${QSO}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="Gal" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of additional information in the galaxy candidates table | ||
| (in_galaxy_candidates) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${Gal}%7d%5cvMore%7b-source=I/356/galcand%5c%26Source=${Source}%7d%7b${Gal}%7d%5celse%7b${Gal}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="NSS" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/7] Flag indicating the availability of additional information in the various Non-Single Star tables | ||
| (non_single_star) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${NSS}%7d%5cvMore%7b-source=I/357/tb%2a%5c%26Source=${Source}%7d%7b${NSS}%7d%5celse%7b${NSS}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="XPcont" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of mean BP/RP spectrum in continuous representation for this source | ||
| (has_xp_continuous) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${XPcont}%7d%5cvMore%7b-source=I/355/xpco%2a%5c%26Source=${Source}%7d%7b${XPcont}%7d%5celse%7b${XPcont}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="XPsamp" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of mean BP/RP spectrum in sampled form for this source | ||
| (has_xp_sampled) | ||
| </DESCRIPTION> | ||
| <LINK content-type="timeserie/votable" | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${XPsamp}%7d%5cvizContent%7bspectrum%7d%5cvplotTS%7bI/355%7d%7b.graph_sql_xpsamp%7d%7bPos=${RA_ICRS}${DE_ICRS}%26Source=${Source}%7d%7b${XPsamp}%7d%5celse%7b${XPsamp}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="RVS" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of mean RVS spectrum for this source (has_rvs)</DESCRIPTION> | ||
| <LINK content-type="timeserie/votable" | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${RVS}%7d%5cvizContent%7btimeSerie%7d%5cvplotTS%7bI/355%7d%7b.graph_sql_rvs%7d%7bPos=${RA_ICRS}${DE_ICRS}%26Source=${Source}%7d%7b${RVS}%7d%5celse%7b${RVS}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="EpochPh" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of epoch photometry for this source (has_epoch_photometry) | ||
| </DESCRIPTION> | ||
| <LINK content-type="timeserie/votable" | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${EpochPh}%7d%5cvizContent%7btimeSerie%7d%5cvplotTS%7bI/355%7d%7b.graph_sql_epphot%7d%7bPos=${RA_ICRS}${DE_ICRS}%26Source=${Source}%7d%7b${EpochPh}%7d%5celse%7b${EpochPh}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="EpochRV" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of epoch radial velocity for this source (has_epoch_rv) | ||
| </DESCRIPTION> | ||
| <LINK | ||
| href="http://vizier.cds.unistra.fr/viz-bin/nph-htx/A?%5cifmatch%7b1%7d%7b${EpochRV}%7d%5cvMore%7b-source=I/358/veprv%5c%26Source=${Source}%7d%7b${EpochRV}%7d%5celse%7b${EpochRV}%7d%5cfi" /> | ||
| </FIELD> | ||
| <FIELD name="MCMCGSP" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of GSP-Phot MCMC samples for this source (has_mcmc_gspphot) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="MCMCMSC" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating the availability of MSC MCMC samples for this source (has_mcmc_msc)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="And" ucd="meta.code.status" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[0/1] Flag indicating that the source is present in the Gaia Andromeda Photometric Survey (GAPS) | ||
| (in_andromeda_survey) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="Teff" ucd="phys.temperature.effective" datatype="double" width="7" precision="1" unit="K"><!-- ucd="PHYS_TEMP_EFFEC" --> | ||
| <DESCRIPTION>? Effective temperature from GSP-Phot Aeneas best library using BP/RP spectra (teff_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="logg" ucd="phys.gravity" datatype="double" width="7" precision="4" unit="log(cm.s**-2)"><!-- ucd="PHYS_GRAVITY_SURFACE" --> | ||
| <DESCRIPTION>? Surface gravity from GSP-Phot Aeneas best library using BP/RP spectra (logg_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="[Fe/H]" ID="__Fe_H_" ucd="phys.abund.Z" datatype="double" width="7" precision="4" unit=""><!-- ucd="PHYS_ABUND_FE/H" --> | ||
| <DESCRIPTION>? Iron abundance from GSP-Phot Aeneas best library using BP/RP spectra (mh_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="Dist" ucd="pos.distance;pos.eq" datatype="double" width="10" precision="4" unit="pc"><!-- ucd="PHYS_DISTANCE_TRUE" --> | ||
| <DESCRIPTION>? Distance from GSP-Phot Aeneas best library using BP/RP spectra (distance_gspphot)</DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="A0" ucd="phys.absorption;em.opt" datatype="double" width="7" precision="4" unit="mag"><!-- ucd="PHOT_EXTINCTION_TOTAL" --> | ||
| <DESCRIPTION>? Monochromatic extinction A_0 at 547.7nm from GSP-Phot Aeneas best library using BP/RP spectra | ||
| (azero_gspphot) | ||
| </DESCRIPTION> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="HIP" ucd="meta.number;phys.atmol.number" datatype="int" width="6"><!-- ucd="ID_NUMBER" --> | ||
| <DESCRIPTION>? HIP cross-id number, van Leeuwen, Cat. I/311 (hip_original_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-2147483648" /> | ||
| </FIELD> | ||
| <FIELD name="PS1" ucd="meta.id.cross" datatype="long" width="18"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? PS1 cross-id name, Chambers et al., Cat. II/349 (ps1_original_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-9223372036854775808" /> | ||
| </FIELD> | ||
| <FIELD name="SDSS13" ucd="meta.id.cross" datatype="long" width="19"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? SDSS name, Albareti et al., 2017ApJS..233...25A (sdss13_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-9223372036854775808" /> | ||
| </FIELD> | ||
| <FIELD name="SKYM2" ucd="meta.id.cross" datatype="int" width="9"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? SkyMapperDR2 cross-id name, Onken et al., 2019PASA...36...33O (skym2_original_ext_source_id) | ||
| </DESCRIPTION> | ||
| <VALUES null="-2147483648" /> | ||
| </FIELD> | ||
| <FIELD name="TYC2" ucd="meta.id.cross" datatype="char" arraysize="12*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>Tycho-2 cross-id name, Hog et al., Cat. I/259 (tyc2_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="URAT1" ucd="meta.id.cross" datatype="char" arraysize="15*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>URAT1 name, Zacharias et al., Cat. I/329 (urat1_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="AllWISE" ucd="meta.id.cross" datatype="char" arraysize="19*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>ALLWISE cross-id name, Cutri et al., Cat. II/328 (allwise_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="APASS9" ucd="meta.id.cross" datatype="int" width="8"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>? APASS9 identification, Henden et al., Cat. II/336 (apass9_original_ext_source_id)</DESCRIPTION> | ||
| <VALUES null="-2147483648" /> | ||
| </FIELD> | ||
| <FIELD name="GSC23" ucd="meta.id.cross" datatype="char" arraysize="10*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>GSC2.3 cross-id name, Lasker et al., Cat. I/305 (gsc23_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAVE5" ucd="meta.id.cross" datatype="char" arraysize="16*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>RAVE DR5 cross-id name, Kunder et al., Cat. III/279 (rave5_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="2MASS" ucd="meta.id.cross" ID="_2MASS" datatype="char" arraysize="17*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>2MASS cross-id name, Cutri et al., Cat. II/246 (twomass_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAVE6" ucd="meta.id.cross" datatype="char" arraysize="21*"><!-- ucd="ID_CROSSID" --> | ||
| <DESCRIPTION>RAVE DR6 cross-id name, Steinmetz et al., Cat. III/283 (rave6_original_ext_source_id)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="RAJ2000" ucd="pos.eq.ra" datatype="double" width="15" precision="11" unit="deg"><!-- ucd="POS_EQ_RA_OTHER" --> | ||
| <DESCRIPTION>Barycentric right ascension (ICRS) at Ep=2000.0 (added by CDS) (ra2000)</DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD name="DEJ2000" ucd="pos.eq.dec" datatype="double" width="15" precision="11" unit="deg"><!-- ucd="POS_EQ_DEC_OTHER" --> | ||
| <DESCRIPTION>Barycentric declination (ICRS) at Ep=2000.0 (added by CDS) (dec2000)</DESCRIPTION> | ||
| </FIELD> | ||
| <DATA> | ||
| <TABLEDATA> | ||
| <TR> | ||
| <TD>307.7911702004070</TD> | ||
| <TD>+20.4311044212247</TD> | ||
| <TD>Gaia DR3 1816065554621487360</TD> | ||
| <TD>307.79115807079</TD> | ||
| <TD>+20.43108005561</TD> | ||
| <TD>1816065554621487360</TD> | ||
| <TD>0.0511</TD> | ||
| <TD>0.0477</TD> | ||
| <TD>0.4319</TD> | ||
| <TD>0.0691</TD> | ||
| <TD>6.049</TD> | ||
| <TD>-2.557</TD> | ||
| <TD>0.064</TD> | ||
| <TD>-5.482</TD> | ||
| <TD>0.067</TD> | ||
| <TD>0.1212</TD> | ||
| <TD>0.1337</TD> | ||
| <TD>-0.4109</TD> | ||
| <TD>-0.0072</TD> | ||
| <TD>0.0069</TD> | ||
| <TD>-0.0085</TD> | ||
| <TD>-0.2983</TD> | ||
| <TD>-0.2603</TD> | ||
| <TD>-0.0251</TD> | ||
| <TD>0.2688</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>1</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>1</TD> | ||
| <TD>1</TD> | ||
| <TD>0</TD> | ||
| <TD>4696.2</TD> | ||
| <TD>4.1928</TD> | ||
| <TD>-0.7942</TD> | ||
| <TD>2428.5532</TD> | ||
| <TD>0.0380</TD> | ||
| <TD></TD> | ||
| <TD>132513077911637877</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>URAT1-553569515</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD017546</TD> | ||
| <TD></TD> | ||
| <TD>20310987+2025519</TD> | ||
| <TD></TD> | ||
| <TD>307.79117020041</TD> | ||
| <TD>20.43110442122</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7958370989668</TD> | ||
| <TD>+20.4325479549513</TD> | ||
| <TD>Gaia DR3 1816065558924798592</TD> | ||
| <TD>307.79582391363</TD> | ||
| <TD>+20.43253083107</TD> | ||
| <TD>1816065558924798592</TD> | ||
| <TD>0.3203</TD> | ||
| <TD>0.2898</TD> | ||
| <TD>-0.5553</TD> | ||
| <TD>0.4195</TD> | ||
| <TD>4.751</TD> | ||
| <TD>-2.780</TD> | ||
| <TD>0.395</TD> | ||
| <TD>-3.853</TD> | ||
| <TD>0.426</TD> | ||
| <TD>0.3740</TD> | ||
| <TD>0.1981</TD> | ||
| <TD>-0.3253</TD> | ||
| <TD>-0.0486</TD> | ||
| <TD>0.0632</TD> | ||
| <TD>-0.0608</TD> | ||
| <TD>-0.1303</TD> | ||
| <TD>-0.2989</TD> | ||
| <TD>-0.0876</TD> | ||
| <TD>0.4716</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>132513077957999584</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD017483</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.79583709897</TD> | ||
| <TD>20.43254795495</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7973736604703</TD> | ||
| <TD>+20.4355882715396</TD> | ||
| <TD>Gaia DR3 1816065558920966528</TD> | ||
| <TD>307.79737366047</TD> | ||
| <TD>+20.43558827154</TD> | ||
| <TD>1816065558920966528</TD> | ||
| <TD>6.0643</TD> | ||
| <TD>2.1063</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0.7514</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>132523077973693273</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.79737366047</TD> | ||
| <TD>20.43558827154</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7885745651585</TD> | ||
| <TD>+20.4301331822264</TD> | ||
| <TD>Gaia DR3 1816065558924801792</TD> | ||
| <TD>307.78856137441</TD> | ||
| <TD>+20.43011713943</TD> | ||
| <TD>1816065558924801792</TD> | ||
| <TD>0.1196</TD> | ||
| <TD>0.1127</TD> | ||
| <TD>0.0910</TD> | ||
| <TD>0.1671</TD> | ||
| <TD>4.557</TD> | ||
| <TD>-2.781</TD> | ||
| <TD>0.153</TD> | ||
| <TD>-3.610</TD> | ||
| <TD>0.165</TD> | ||
| <TD>0.1448</TD> | ||
| <TD>0.1580</TD> | ||
| <TD>-0.3400</TD> | ||
| <TD>0.0468</TD> | ||
| <TD>0.0149</TD> | ||
| <TD>0.0299</TD> | ||
| <TD>-0.2083</TD> | ||
| <TD>-0.2178</TD> | ||
| <TD>0.0615</TD> | ||
| <TD>0.3266</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>1</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>5071.5</TD> | ||
| <TD>4.6975</TD> | ||
| <TD>-0.7109</TD> | ||
| <TD>2923.6248</TD> | ||
| <TD>0.0090</TD> | ||
| <TD></TD> | ||
| <TD>132513077885716709</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>URAT1-553569502</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD017266</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.78857456516</TD> | ||
| <TD>20.43013318223</TD> | ||
| </TR> | ||
| <TR> | ||
| <TD>307.7897816527446</TD> | ||
| <TD>+20.4315208963567</TD> | ||
| <TD>Gaia DR3 1816065554622254464</TD> | ||
| <TD>307.78977228741</TD> | ||
| <TD>+20.43150439876</TD> | ||
| <TD>1816065554622254464</TD> | ||
| <TD>0.3688</TD> | ||
| <TD>0.3801</TD> | ||
| <TD>-0.6243</TD> | ||
| <TD>0.5059</TD> | ||
| <TD>4.205</TD> | ||
| <TD>-1.975</TD> | ||
| <TD>0.444</TD> | ||
| <TD>-3.712</TD> | ||
| <TD>0.498</TD> | ||
| <TD>0.2553</TD> | ||
| <TD>0.0889</TD> | ||
| <TD>-0.3890</TD> | ||
| <TD>-0.0365</TD> | ||
| <TD>-0.0773</TD> | ||
| <TD>-0.0307</TD> | ||
| <TD>-0.2998</TD> | ||
| <TD>-0.2452</TD> | ||
| <TD>0.0025</TD> | ||
| <TD>0.3249</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>132513077897708356</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>N2PD096440</TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD></TD> | ||
| <TD>307.78978165274</TD> | ||
| <TD>20.43152089636</TD> | ||
| </TR> | ||
| </TABLEDATA> | ||
| </DATA> | ||
| </TABLE> | ||
| <INFO name="matches" value="5">matching records</INFO> | ||
| <INFO name="Warning" value="No center provided++++" /> | ||
| <INFO name="Warning" value="increase the precision for computed column 14" /> | ||
| <INFO name="Warning" value="increase the precision for computed column 14" /> | ||
| <INFO name="Warning" value="truncated result (maxtup=5)" /> | ||
| <INFO name="QUERY_STATUS" value="OVERFLOW"> value="truncated result (maxtup=5)"</INFO> | ||
| </RESOURCE> | ||
| </VOTABLE> |
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <VOTABLE version="1.1" xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <INFO name="QUERY_STATUS" value="ERROR"> | ||
| <DESCRIPTION>PhotCalID not found: zaada</DESCRIPTION> | ||
| </INFO> | ||
| </VOTABLE> |
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <INSTANCE dmrole="" dmtype="Phot:PhotCal"> | ||
| <ATTRIBUTE dmrole="Phot:PhotCal.identifier" dmtype="ivoa:string" value="SLOAN/SDSS.g/AB"/> | ||
| <INSTANCE dmrole="Phot:PhotCal.zeroPoint" dmtype="Phot:AsinhZeroPoint"> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.type" dmtype="ivoa:integer" value="1"/> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.referenceMagnitudeValue" dmtype="ivoa:real" value="0"/> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.referenceMagnitudeError" dmtype="ivoa:real" value="0"/> | ||
| <ATTRIBUTE dmrole="Phot:AsinhZeroPoint.softeningParameter" dmtype="ivoa:real" value="0.00000000009"/> | ||
| <INSTANCE dmrole="Phot:AsinhZeroPoint.flux" dmtype="Phot:Flux"> | ||
| <ATTRIBUTE dmrole="Phot:Flux.ucd" dmtype="Phot:UCD" value="phot.flux.density"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.unitexpression" dmtype="ivoa:Unit" value="Jy"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.value" dmtype="ivoa:real" value="3631"/> | ||
| <ATTRIBUTE dmrole="Phot:Flux.error" dmtype="ivoa:real" value="0"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.magnitudeSystem" dmtype="Phot:MagnitudeSystem"> | ||
| <ATTRIBUTE dmrole="Phot:MagnitudeSystem.type" dmtype="Phot:TypeOfMagSystem" value="AB"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter" dmtype="Phot:photometryFilter"> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.fpsIdentifier" dmtype="ivoa:string" value="ivo://svo/fps"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.identifier" dmtype="ivoa:string" value="SLOAN/SDSS.g"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.name" dmtype="ivoa:string" value="SDSS.g"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.description" dmtype="ivoa:string" value="SDSS g full transmission"/> | ||
| <ATTRIBUTE dmrole="Phot:PhotometryFilter.bandName" dmtype="ivoa:string" value="g"/> | ||
| <INSTANCE dmrole="Phot:PhotCal.photometryFilter.bandwidth" dmtype="Phot:Bandwidth"> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.ucd" dmtype="Phot:UCD" value="instr.bandwidth"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.unitexpression" dmtype="ivoa:Unit" value=""/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.extent" dmtype="ivoa:real" value="1064.6831251068"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.start" dmtype="ivoa:real" value="3797.6384743979"/> | ||
| <ATTRIBUTE dmrole="Phot:Bandwidth.stop" dmtype="ivoa:real" value="3797.6384743979"/> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.transmissionCurve" dmtype="Phot:TransmissionCurve"> | ||
| <INSTANCE dmrole="Phot:TransmissionCurve.access" dmtype="Phot:Access"> | ||
| <ATTRIBUTE dmrole="Phot:Access.reference" dmtype="ivoa:anyURI" value="http://svo2.cab.inta-csic.es/theory/fps/fps.php?ID=SLOAN/SDSS.g"/> | ||
| <ATTRIBUTE dmrole="Phot:Access.size" dmtype="ivoa:integer" value="2"/> | ||
| <ATTRIBUTE dmrole="Phot:Access.format" dmtype="ivoa:string" value="application/x-votable+xml"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| <INSTANCE dmrole="Phot:PhotometryFilter.spectralLocation" dmtype="Phot:SpectralLocation"> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.ucd" dmtype="Phot:UCD" value="em.wl;meta.main"/> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.unitexpression" dmtype="ivoa:Unit" value="Angstrom"/> | ||
| <ATTRIBUTE dmrole="Phot:SpectralLocation.value" dmtype="ivoa:real" value="4702.4953002767"/> | ||
| </INSTANCE> | ||
| </INSTANCE> | ||
| </INSTANCE> |
| """ | ||
| This module contains test cases for validating the generation of mapping dictionaries that allow | ||
| to extract Mivot instances from INFO located in the VOTable header | ||
| """ | ||
| import pytest | ||
| from astropy.io.votable import parse | ||
| from astropy.utils.data import get_pkg_data_filename | ||
| from pyvo.utils import activate_features | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot.writer.header_mapper import HeaderMapper | ||
| # Enable MIVOT-specific features in the pyvo library | ||
| activate_features("MIVOT") | ||
| data_origin_mapping = { | ||
| "service_protocol": | ||
| "ivo://ivoa.net/std/ConeSearch/v1.03", | ||
| "request_date": | ||
| "2025-04-07T12:06:32", | ||
| "request": ("https://cdsarc.cds.unistra.fr/beta/viz-bin/mivotconesearch" | ||
| "/I/329/urat1?RA=52.26708&DEC=59.94027&SR=0.05"), | ||
| "contact": | ||
| "cds-question@unistra.fr", | ||
| "server_software": | ||
| "7.4.6", | ||
| "publisher": | ||
| "CDS", | ||
| "dataOrigin": [{ | ||
| "ivoid": "ivo://cds.vizier/i/329", | ||
| "creators": ["Zacharias N."], | ||
| "cites": "bibcode:2015AJ....150..101Z", | ||
| "original_date": "2015", | ||
| "reference_url": "https://cdsarc.cds.unistra.fr/viz-bin/cat/I/329", | ||
| "rights_uri": "https://cds.unistra.fr/vizier-org/licences_vizier.html", | ||
| "articles": [{ | ||
| "editor": "Astronomical Journal (AAS)" | ||
| }] | ||
| }] | ||
| } | ||
| coosys_mappings = [{"spaceRefFrame": "ICRS", "epoch": "2345"}] | ||
| timesys_mappings = [{"timescale": "TCB"}] | ||
| @pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+") | ||
| def test_all(): | ||
| """ | ||
| checks that the mapping dictionaries extracte from the VOTable match the expected ones | ||
| """ | ||
| votable = parse(get_pkg_data_filename("data/test.header_extraction.xml")) | ||
| builder = HeaderMapper(votable) | ||
| assert builder.extract_origin_mapping() == data_origin_mapping | ||
| assert builder.extract_coosys_mapping() == coosys_mappings | ||
| assert builder.extract_timesys_mapping() == timesys_mappings | ||
| @pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+") | ||
| def test_field_extraction(): | ||
| """ | ||
| checks that the epochPosition mapping dictionaries extracted from | ||
| the VOTable columns match the expected ones | ||
| """ | ||
| votable = parse(get_pkg_data_filename("data/test.header_extraction.1.xml")) | ||
| builder = HeaderMapper(votable) | ||
| mapping, error_mapping = builder.extract_epochposition_mapping() | ||
| assert mapping == {"longitude": "RA_ICRS", "latitude": "DE_ICRS", "parallax": "Plx", | ||
| "pmLongitude": "pmRA", "pmLatitude": "pmDE", "radialVelocity": "RV"} | ||
| assert error_mapping == {"position": {"class": "PErrorSym2D", | ||
| "sigma1": "e_RA_ICRS", "sigma2": "e_DE_ICRS"}, | ||
| "parallax": {"class": "PErrorSym1D", "sigma": "e_Plx"}, | ||
| "properMotion": {"class": "PErrorSym2D", | ||
| "sigma1": "e_pmRA", "sigma2": "e_pmDE"}, | ||
| "radialVelocity": {"class": "PErrorSym1D", "sigma": "e_RV"}} | ||
| votable = parse(get_pkg_data_filename("data/test.header_extraction.2.xml")) | ||
| builder = HeaderMapper(votable) | ||
| mapping, error_mapping = builder.extract_epochposition_mapping() | ||
| assert mapping == {"obsDate": {"dateTime": "ObsDate", | ||
| "representation": "iso"}, | ||
| "longitude": "RAB1950", | ||
| "latitude": "DEB1950" | ||
| } |
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| This module contains test cases for validating the functionality of MivotInstance, MivotAnnotations, | ||
| and related components in the pyvo.mivot package. These tests ensure that the classes behave as | ||
| expected, including error handling and XML generation for data models. | ||
| """ | ||
| import os | ||
| import pytest | ||
| from unittest.mock import patch | ||
| from astropy.io.votable import parse | ||
| from astropy.utils.data import get_pkg_data_contents, get_pkg_data_filename | ||
| from pyvo.utils import activate_features | ||
| 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 | ||
| # Enable MIVOT-specific features in the pyvo library | ||
| activate_features("MIVOT") | ||
| # File paths for test data | ||
| votable_path = os.path.realpath( | ||
| os.path.join(__file__, "..", "data", "test.mivot_viewer.no_mivot.xml") | ||
| ) | ||
| data_path = os.path.realpath( | ||
| os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") | ||
| ) | ||
| @pytest.fixture() | ||
| def mocked_fps_grvs(mocker): | ||
| def callback(request, context): | ||
| return bytes(get_pkg_data_contents('data/filter_gaia_grvs.xml'), "utf8") | ||
| with mocker.register_uri( | ||
| 'GET', 'http://svo2.cab.inta-csic.es/svo/theory/fps/fpsmivot.php?PhotCalID=GAIA/GAIA3.Grvs/AB', | ||
| content=callback | ||
| ) as matcher: | ||
| yield matcher | ||
| @pytest.fixture() | ||
| def mocked_fps_grp(mocker): | ||
| def callback(request, context): | ||
| return bytes(get_pkg_data_contents('data/filter_gaia_grp.xml'), "utf8") | ||
| with mocker.register_uri( | ||
| 'GET', 'http://svo2.cab.inta-csic.es/svo/theory/fps/fpsmivot.php?PhotCalID=GAIA/GAIA3.Grp/AB', | ||
| content=callback | ||
| ) as matcher: | ||
| yield matcher | ||
| @pytest.fixture | ||
| def mocked_fps(): | ||
| with patch('requests.get') as mock_get: | ||
| yield mock_get | ||
| @pytest.mark.filterwarnings("ignore:root:::") | ||
| def add_color(builder): | ||
| filter_ids = {"high": "GAIA/GAIA3.Grp/AB", "low": "GAIA/GAIA3.Grvs/AB"} | ||
| mapping = {"value": 8.76, "definition": "ColorIndex", | ||
| "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" | ||
| mapping = {"value": "GRVSmag", | ||
| "error": {"class": "PErrorAsym1D", "low": 1, "high": 3} | ||
| } | ||
| semantics = {"description": "Grvs magnitude", | ||
| "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#magnitude", | ||
| "label": "magnitude"} | ||
| builder.add_mango_brightness(photcal_id=photcal_id, mapping=mapping, semantics=semantics) | ||
| def add_epoch_positon(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}, | ||
| "correlations": {"isCovariance": True, | ||
| "longitudeLatitude": "RADEcor", | ||
| "latitudePmLongitude": "DEpmRAcor", "latitudePmLatitude": "DEpmDEcor", | ||
| "longitudePmLongitude": "RApmRAcor", "longitudePmLatitude": "RApmDEcor", | ||
| "longitudeParallax": "RAPlxcor", "latitudeParallax": "DEPlxcor", | ||
| "pmLongitudeParallax": "PlxpmRAcor", "pmLatitudeParallax": "PlxpmDEcor", | ||
| }, | ||
| "errors": {"position": {"class": "PErrorSym2D", "sigma1": "e_RA_ICRS", "sigma2": "e_DE_ICRS"}, | ||
| "properMotion": {"class": "PErrorSym2D", "sigma1": "e_pmRA", "sigma2": "e_pmDE"}, | ||
| "parallax": {"class": "PErrorSym1D", "sigma": "e_Plx"}, | ||
| "radialVelocity": {"class": "PErrorSym1D", "sigma": "e_RV"} | ||
| } | ||
| } | ||
| 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(): | ||
| votable_filename = get_pkg_data_filename("data/test.mango_annoter.xml") | ||
| votable = parse(votable_filename) | ||
| builder = InstancesFromModels(votable, dmid="DR3Name") | ||
| # pylint: disable=E501 | ||
| builder.add_query_origin( | ||
| {"service_protocol": "ASU", | ||
| "request_date": "2024-03-21T15:16:08", | ||
| "request": ("https://vizier.cds.unistra.fr/viz-bin/votable?-oc.form=dec&-out.max=5&" | ||
| "-out.add=_r&-out.add=_RAJ,_DEJ&-sort=_r&-c.eq=J2000&-c.r= 2&" | ||
| "-c.u=arcmin&-c.geom=r&-source=I/355/gaiadr3&-order=I&" | ||
| "-out.orig=standard&-out=DR3Name&-out=RA_ICRS&-out=DE_ICRS&" | ||
| "-out=Source&-out=e_RA_ICRS&-out=e_DE_ICRS&-out=Plx&" | ||
| "-out=e_Plx&-out=PM&-out=pmRA&-out=e_pmRA&-out=pmDE&" | ||
| "-out=e_pmDE&-out=RADEcor&-out=RAPlxcor&-out=RApmRAcor&" | ||
| "-out=RApmDEcor&-out=DEPlxcor&-out=DEpmRAcor&-out=DEpmDEcor&" | ||
| "-out=PlxpmRAcor&-out=PlxpmDEcor&-out=pmRApmDEcor&-out=RV&" | ||
| "-out=e_RV&-out=Vbroad&-out=GRVSmag&-out=QSO&-out=Gal&-out=NSS&" | ||
| "-out=XPcont&-out=XPsamp&-out=RVS&-out=EpochPh&-out=EpochRV&" | ||
| "-out=MCMCGSP&-out=MCMCMSC&-out=And&-out=Teff&-out=logg&" | ||
| "-out=[Fe/H]&-out=Dist&-out=A0&-out=HIP&-out=PS1&-out=SDSS13&" | ||
| "-out=SKYM2&-out=TYC2&-out=URAT1&-out=AllWISE&-out=APASS9&" | ||
| "-out=GSC23&-out=RAVE5&-out=2MASS&-out=RAVE6&-out=RAJ2000&" | ||
| "-out=DEJ2000&"), | ||
| "contact": "cds-question@unistra.fr", | ||
| "server_software": "7.33.3", | ||
| "publisher": "CDS", | ||
| "dataOrigin": [{"ivoid": "ivo://cds.vizier/i/355", | ||
| "creators": ["Gaia collaboration"], | ||
| "cites": "bibcode:2022yCat.1355....0G, ""doi:10.26093/cds/vizier.1355", | ||
| "original_date": "2022", | ||
| "reference_url": "https://cdsarc.cds.unistra.fr/viz-bin/cat/I/355", | ||
| "rights_uri": "https://cds.unistra.fr/vizier-org/licences_vizier.html", | ||
| "articles": [{"identifier": "doi:10.1051/0004-6361/202039657e]", | ||
| "editor": "A&A"}] | ||
| }] | ||
| }) | ||
| add_color(builder) | ||
| add_photometry(builder) | ||
| add_epoch_positon(builder) | ||
| builder.pack_into_votable() | ||
| XmlUtils.pretty_print(builder._annotation.mivot_block) | ||
| assert XmlUtils.strip_xml(builder._annotation.mivot_block) == ( | ||
| XmlUtils.strip_xml(get_pkg_data_contents("data/reference/mango_object.xml")) | ||
| ) | ||
| @pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+") | ||
| def test_extraction_from_votable_header(): | ||
| """ test that the automatic mapping extraction is well connected with the annoter | ||
| """ | ||
| votable_filename = get_pkg_data_filename("data/test.header_extraction.1.xml") | ||
| votable = parse(votable_filename) | ||
| builder = InstancesFromModels(votable, dmid="URAT1") | ||
| builder.extract_frames() | ||
| builder.extract_data_origin() | ||
| epoch_position_mapping = builder.extract_epoch_position_parameters() | ||
| builder.add_mango_epoch_position(**epoch_position_mapping) | ||
| builder.pack_into_votable() | ||
| assert XmlUtils.strip_xml(builder._annotation.mivot_block) == ( | ||
| XmlUtils.strip_xml(get_pkg_data_contents("data/reference/test_header_extraction.xml")) | ||
| ) |
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| This module contains test cases for validating the functionality of MivotInstance, MivotAnnotations, | ||
| and related components in the pyvo.mivot package. These tests ensure that the classes behave as | ||
| expected, including error handling and XML generation for data models. | ||
| """ | ||
| import os | ||
| import pytest | ||
| from pyvo.utils import activate_features | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot.utils.exceptions import MappingError | ||
| from pyvo.mivot.utils.xml_utils import XmlUtils | ||
| from pyvo.mivot.writer.annotations import MivotAnnotations | ||
| from pyvo.mivot.writer.instance import MivotInstance | ||
| # Enable MIVOT-specific features in the pyvo library | ||
| activate_features("MIVOT") | ||
| # File paths for test data | ||
| votable_path = os.path.realpath( | ||
| os.path.join(__file__, "..", "data", "test.mivot_viewer.no_mivot.xml") | ||
| ) | ||
| data_path = os.path.realpath( | ||
| os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") | ||
| ) | ||
| @pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+") | ||
| def test_MivotInstance(): | ||
| """ | ||
| Test the MivotInstance class for various operations including attribute addition, | ||
| reference addition, and XML generation. Verifies that invalid operations raise | ||
| the expected MappingError. | ||
| """ | ||
| with pytest.raises(MappingError): | ||
| MivotInstance("") | ||
| instance1 = MivotInstance("model:type.inst", dmid="id1") | ||
| with pytest.raises(MappingError): | ||
| instance1.add_attribute( | ||
| dmrole="model:type.inst.role1", value="value1", unit="m/s" | ||
| ) | ||
| with pytest.raises(MappingError): | ||
| instance1.add_attribute( | ||
| dmtype="model:type.att1", dmrole="model:type.inst.role1" | ||
| ) | ||
| with pytest.raises(MappingError): | ||
| instance1.add_reference(dmref="dmreference") | ||
| with pytest.raises(MappingError): | ||
| instance1.add_reference(dmrole="model:type.inst.role2") | ||
| with pytest.raises(MappingError): | ||
| instance1.add_instance("azerty") | ||
| instance1.add_reference(dmrole="model:type.inst.role2", dmref="dmreference") | ||
| instance1.add_attribute( | ||
| dmtype="model:type.att1", | ||
| dmrole="model:type.inst.role1", | ||
| value="*value1", | ||
| unit="m/s", | ||
| ) | ||
| assert XmlUtils.strip_xml(instance1.xml_string()) == ( | ||
| "<INSTANCEdmtype=model:type.instdmid=id1>" | ||
| + "<REFERENCEdmrole=model:type.inst.role2dmref=dmreference/>" | ||
| + "<ATTRIBUTEdmtype=model:type.att1dmrole=model:type.inst.role1unit=m/svalue=value1/>" | ||
| + "</INSTANCE>" | ||
| ) | ||
| @pytest.mark.skipif(not check_astropy_version(), reason="need astropy 6+") | ||
| def test_MivotAnnotations(): | ||
| """ | ||
| Test the MivotAnnotations class for template and global instance addition. Verifies | ||
| that invalid operations raise the expected MappingError. | ||
| """ | ||
| mb = MivotAnnotations() | ||
| with pytest.raises(MappingError): | ||
| mb.add_templates(12) | ||
| with pytest.raises(MappingError): | ||
| mb.add_globals(12) |
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from .annotations import MivotAnnotations | ||
| from .instance import MivotInstance | ||
| from .instances_from_models import InstancesFromModels | ||
| from .header_mapper import HeaderMapper | ||
| from .mango_object import MangoObject, Property |
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| MivotAnnotations: A utility module to build and manage MIVOT annotations. | ||
| """ | ||
| import os | ||
| import logging | ||
| try: | ||
| import xmlschema | ||
| except ImportError: | ||
| xmlschema = None | ||
| # Use defusedxml only if already present in order to avoid a new dependency. | ||
| try: | ||
| from defusedxml import ElementTree as etree | ||
| except ImportError: | ||
| from xml.etree import ElementTree as etree | ||
| from astropy.io.votable.tree import VOTableFile, Resource | ||
| try: | ||
| from astropy.io.votable.tree import MivotBlock | ||
| except ImportError: | ||
| pass | ||
| from astropy.io.votable import parse | ||
| from astropy import version | ||
| from pyvo.utils.prototype import prototype_feature | ||
| from pyvo.mivot.utils.xml_utils import XmlUtils | ||
| from pyvo.mivot.utils.exceptions import MappingError, AstropyVersionException | ||
| from pyvo.mivot.writer.instance import MivotInstance | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| __all__ = ["MivotAnnotations"] | ||
| @prototype_feature("MIVOT") | ||
| class MivotAnnotations: | ||
| """ | ||
| This module provides a class to construct, validate, and insert MIVOT | ||
| blocks into VOTable files. | ||
| The MIVOT block, represented as an XML structure, is used for | ||
| data model annotations in the IVOA ecosystem. | ||
| The main features are: | ||
| - Construct the MIVOT block step-by-step with various components. | ||
| - Validate the MIVOT block against the MIVOT XML schema (if ``xmlschema`` is installed). | ||
| - Embed the MIVOT block into an existing VOTable file. | ||
| The MIVOT block is constructed as a string to maintain compatibility with the Astropy API. | ||
| Attributes | ||
| ---------- | ||
| suggested_space_frames: string array, class attribute | ||
| A warning is emitted if a frame not in this list is used to build a space frame. | ||
| This list matches https://www.ivoa.net/rdf/refframe/2022-02-22/refframe.html. | ||
| suggested_ref_positions: string array, class attribute | ||
| A warning is emitted if a reference position not in this list is | ||
| used to build a space or a time frame. | ||
| suggested_time_frames: string array, class attribute | ||
| A warning is emitted if a frame not in this list is used to build a space frame. | ||
| This list matches https://www.ivoa.net/rdf/timescale/2019-03-15/timescale.html. | ||
| """ | ||
| def __init__(self): | ||
| """ | ||
| """ | ||
| # Dictionary containing models with their names as keys and URLs as values | ||
| self._models = {} | ||
| # str: Indicates the success status of the annotation process.s | ||
| self._report_status = True | ||
| # str: message associated with the report, used in the REPORT block. | ||
| self._report_message = "Generated by pyvo.mivot.writer" | ||
| # list(str or MivotInstance): GLOBALS blocks to be included in the MIVOT block. | ||
| self._globals = [] | ||
| # list(str or MivotInstance): TEMPLATES blocks to be included in the MIVOT block. | ||
| self._templates = [] | ||
| # str: An optional ID for the TEMPLATES block. | ||
| self._templates_id = "" | ||
| # str: list of the dmid of the INSTANCE stored in the GLOBALS | ||
| self._dmids = [] | ||
| # str: Complete MIVOT block as a string | ||
| self._mivot_block = "" | ||
| @property | ||
| def mivot_block(self): | ||
| """ | ||
| Getter for the whole MIVOT block. | ||
| Returns | ||
| ------- | ||
| str | ||
| Complete MIVOT block as a string. | ||
| """ | ||
| return self._mivot_block | ||
| def _get_report(self): | ||
| """ | ||
| Generate the <REPORT> component of the MIVOT block. | ||
| Returns | ||
| ------- | ||
| str | ||
| The <REPORT> block as a string, indicating the success or failure of the process. | ||
| """ | ||
| if self._report_status: | ||
| return f'<REPORT status="OK">{self._report_message}</REPORT>' | ||
| else: | ||
| return f'<REPORT status="FAILED">{self._report_message}</REPORT>' | ||
| def _get_models(self): | ||
| """ | ||
| Generate the <MODEL> components of the MIVOT block. | ||
| Returns | ||
| ------- | ||
| str | ||
| The <MODEL> components as a formatted string. | ||
| """ | ||
| models_block = "" | ||
| for key, value in self._models.items(): | ||
| if value: | ||
| models_block += f'<MODEL name="{key}" url="{value}" />\n' | ||
| else: | ||
| models_block += f'<MODEL name="{key}" />\n' | ||
| return models_block | ||
| def _get_globals(self): | ||
| """ | ||
| Generate the <GLOBALS> component of the MIVOT block. | ||
| Returns | ||
| ------- | ||
| str | ||
| The <GLOBALS> block as a formatted string. | ||
| """ | ||
| globals_block = "<GLOBALS>\n" | ||
| for glob in self._globals: | ||
| globals_block += f"{glob}\n" | ||
| globals_block += "</GLOBALS>\n" | ||
| return globals_block | ||
| def _get_templates(self): | ||
| """ | ||
| Generate the <TEMPLATES> component of the MIVOT block. | ||
| Returns | ||
| ------- | ||
| str | ||
| The <TEMPLATES> block as a formatted string, or an empty string if no templates are defined. | ||
| """ | ||
| if not self._templates: | ||
| return "" | ||
| if not self._templates_id: | ||
| templates_block = "<TEMPLATES>\n" | ||
| else: | ||
| templates_block = f'<TEMPLATES tableref="{self._templates_id}">\n' | ||
| for templates in self._templates: | ||
| templates_block += f"{templates}\n" | ||
| templates_block += "</TEMPLATES>\n" | ||
| return templates_block | ||
| def build_mivot_block(self, *, templates_id=None, schema_check=True): | ||
| """ | ||
| Build a complete MIVOT block from the declared components and validates it | ||
| against the MIVOT XML schema. | ||
| Parameters | ||
| ---------- | ||
| templates_id : str, optional | ||
| The ID to associate with the <TEMPLATES> block. Defaults to None. | ||
| schema_check : boolean, optional | ||
| Skip the XSD validation if False (use to make test working in local mode). | ||
| Raises | ||
| ------ | ||
| Any exceptions raised during XML validation are not caught and must | ||
| be handled by the caller. | ||
| """ | ||
| if templates_id: | ||
| self._templates_id = templates_id | ||
| self._mivot_block = '<VODML xmlns="http://www.ivoa.net/xml/mivot">\n' | ||
| self._mivot_block += self._get_report() | ||
| self._mivot_block += "\n" | ||
| self._mivot_block += self._get_models() | ||
| self._mivot_block += "\n" | ||
| self._mivot_block += self._get_globals() | ||
| self._mivot_block += "\n" | ||
| self._mivot_block += self._get_templates() | ||
| self._mivot_block += "\n" | ||
| self._mivot_block += "</VODML>\n" | ||
| self._mivot_block = self.mivot_block.replace("\n\n", "\n") | ||
| self._mivot_block = XmlUtils.pretty_string(self._mivot_block) | ||
| if schema_check: | ||
| self.check_xml() | ||
| def add_templates(self, templates_instance): | ||
| """ | ||
| Add an <INSTANCE> element to the <TEMPLATES> block. | ||
| Parameters | ||
| ---------- | ||
| templates_instance : str or MivotInstance | ||
| The <INSTANCE> element to be added. | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``templates_instance`` is neither a string nor an instance of `MivotInstance`. | ||
| """ | ||
| if isinstance(templates_instance, MivotInstance): | ||
| self._templates.append(templates_instance.xml_string()) | ||
| if templates_instance.dmid is not None: | ||
| self._dmids.append(templates_instance.dmid) | ||
| elif isinstance(templates_instance, str): | ||
| self._templates.append(templates_instance) | ||
| else: | ||
| raise MappingError( | ||
| "Instance added to templates must be a string or MivotInstance." | ||
| ) | ||
| def add_globals(self, globals_instance): | ||
| """ | ||
| Add an <INSTANCE> block to the <GLOBALS> block. | ||
| Parameters | ||
| ---------- | ||
| globals_instance : str or MivotInstance | ||
| The <INSTANCE> block to be added. | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``globals_instance`` is neither a string nor an instance of `MivotInstance`. | ||
| """ | ||
| if isinstance(globals_instance, MivotInstance): | ||
| self._globals.append(globals_instance.xml_string()) | ||
| if globals_instance.dmid is not None: | ||
| self._dmids.append(globals_instance.dmid) | ||
| elif isinstance(globals_instance, str): | ||
| self._globals.append(globals_instance) | ||
| else: | ||
| raise MappingError( | ||
| "Instance added to globals must be a string or MivotInstance." | ||
| ) | ||
| def add_model(self, model_name, *, vodml_url=None): | ||
| """ | ||
| Add a <MODEL> element to the MIVOT block. | ||
| Parameters | ||
| ---------- | ||
| model_name : str | ||
| The short name of the model. | ||
| vodml_url : str, optional | ||
| The URL of the VO-DML file associated with the model. | ||
| """ | ||
| self._models[model_name] = vodml_url | ||
| def set_report(self, status, message): | ||
| """ | ||
| Set the <REPORT> element of the MIVOT block. | ||
| Parameters | ||
| ---------- | ||
| status : bool | ||
| The status of the annotation process. True for success, False for failure. | ||
| message : str | ||
| The message associated with the REPORT. | ||
| Notes | ||
| ----- | ||
| If ``status`` is False, all components of the MIVOT block except MODEL and REPORT | ||
| are cleared. | ||
| """ | ||
| self._report_status = status | ||
| self._report_message = message | ||
| if not status: | ||
| self._globals = [] | ||
| self._templates = [] | ||
| def check_xml(self): | ||
| """ | ||
| Validate the MIVOT block against the MIVOT XML schema v1.0. | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If the validation fails. | ||
| Notes | ||
| ----- | ||
| The schema (mivot 1.0) is loaded from a local file to avoid dependency on a remote service. | ||
| """ | ||
| # put here just to improve the test coverage | ||
| root = etree.fromstring(self._mivot_block) | ||
| mivot_block = XmlUtils.pretty_string(root, clean_namespace=False) | ||
| if not xmlschema: | ||
| logging.warning( | ||
| "XML validation skipped: no XML schema validator found. " | ||
| + "Please install it (e.g., pip install xmlschema)." | ||
| ) | ||
| return | ||
| schema = xmlschema.XMLSchema11(os.path.dirname(__file__) + "/mivot-v1.xsd") | ||
| try: | ||
| schema.validate(mivot_block) | ||
| except Exception as excep: | ||
| raise MappingError(f"Validation failed: {excep}") from excep | ||
| def insert_into_votable(self, votable_file, override=False): | ||
| """ | ||
| Insert the MIVOT block into a VOTable. | ||
| Parameters | ||
| ---------- | ||
| votable_file : str or VOTableFile | ||
| The VOTable to be annotated, either as a file path or a ``VOTableFile`` instance. | ||
| override : bool | ||
| If True, overrides any existing annotations in the VOTable. | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If a mapping block already exists and ``override`` is False. | ||
| """ | ||
| if not check_astropy_version(): | ||
| raise AstropyVersionException(f"Astropy version {version.version} " | ||
| "is below the required version 6.0 for the use of MIVOT.") | ||
| if isinstance(votable_file, str): | ||
| votable = parse(votable_file) | ||
| elif isinstance(votable_file, VOTableFile): | ||
| votable = votable_file | ||
| else: | ||
| raise MappingError( | ||
| "votable_file must be a file path string or a VOTableFile instance, " | ||
| "not a {type(votable_file)}." | ||
| ) | ||
| for resource in votable.resources: | ||
| if resource.type == "results": | ||
| for subresource in resource.resources: | ||
| if subresource.type == "meta": | ||
| if not override: | ||
| raise MappingError( | ||
| "A type='meta' resource already exists in the first 'result' resource." | ||
| ) | ||
| else: | ||
| logging.info("Overriding existing type='meta' resource.") | ||
| break | ||
| mivot_resource = Resource() | ||
| mivot_resource.type = "meta" | ||
| mivot_resource.mivot_block = MivotBlock(self._mivot_block) | ||
| resource.resources.append(mivot_resource) |
| """ | ||
| ``HeaderMapper`` class source | ||
| """ | ||
| import logging | ||
| from pyvo.mivot.glossary import Roles, EpochPositionAutoMapping | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| class HeaderMapper: | ||
| """ | ||
| This utility class generates dictionaries from header elements of a VOTable. | ||
| These dictionaries are used as input parameters by `pyvo.mivot.writer.InstancesFromModels` | ||
| to create MIVOT instances that are placed in the GLOBALS block or in the TEMPLATES. | ||
| In the current implementation, the following elements can be extracted: | ||
| - COOSYS -> coords:SpaceSys | ||
| - TIMESYS - coords:TimeSys | ||
| - INFO -> mango:QueryOrigin | ||
| - FIELD -> mango:EpochPosition | ||
| """ | ||
| def __init__(self, votable): | ||
| """ | ||
| Constructor parameters: | ||
| Parameters | ||
| ---------- | ||
| votable : astropy.io.votable.tree.VOTableFile | ||
| parsed votable from which INFO element are processed | ||
| """ | ||
| self._votable = votable | ||
| def _check_votable_head_element(self, parameter): | ||
| """ | ||
| Check that the parameter is a valid value. | ||
| .. note:: | ||
| Vizier uses the ``UNKNOWN`` word to tag not set values | ||
| """ | ||
| return parameter is not None and parameter != "UNKNOWN" | ||
| def _extract_query_origin(self): | ||
| """ | ||
| Create a mapping dictionary from ``INFO`` elements found | ||
| in the VOTable header. | ||
| This dictionary is used to populate the ``mango:QueryOrigin`` attributes | ||
| Returns | ||
| ------- | ||
| dict | ||
| Dictionary that is part of the input parameter for | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_query_origin` | ||
| """ | ||
| mapping = {} | ||
| for info in self._votable.infos: | ||
| if info.name in Roles.QueryOrigin: | ||
| mapping[info.name] = info.value | ||
| return mapping | ||
| def _extract_data_origin(self, resource): | ||
| """ | ||
| Create a mapping dictionary from ``INFO`` elements found | ||
| in the header of the first VOTable resource. | ||
| This dictionary is used to populate the ``mango:QueryOrigin`` part of | ||
| the ``mango:QueryOrigin`` instance. | ||
| Returns | ||
| ------- | ||
| dict | ||
| Dictionary that is part of the input parameter for | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_query_origin` | ||
| """ | ||
| mapping = {} | ||
| article = None | ||
| for info in resource.infos: | ||
| if info.name in Roles.DataOrigin or info.name == "creator": | ||
| if DictUtils.add_array_element(mapping, "dataOrigin"): | ||
| article = {} | ||
| if info.name != "creator": | ||
| article[info.name] = info.value | ||
| else: | ||
| DictUtils.add_array_element(article, "creators") | ||
| article["creators"].append(info.value) | ||
| for info in resource.infos: | ||
| art_ref = {} | ||
| if info.name in Roles.Article: | ||
| DictUtils.add_array_element(article, "articles") | ||
| art_ref[info.name] = info.value | ||
| if art_ref: | ||
| article["articles"].append(art_ref) | ||
| mapping["dataOrigin"].append(article) | ||
| return mapping | ||
| def extract_origin_mapping(self): | ||
| """ | ||
| Create a mapping dictionary from all VOTable ``INFO`` elements. | ||
| This dictionary is used to build a ``mango:QueryOrigin`` INSTANCE | ||
| - INFO elements located in the VOTable header are used to build the ``mango:QueryOrigin`` | ||
| part which scope is the whole VOtable by construction (one query -> one VOTable) | ||
| - INFO elements located in the resource header are used to build the ``mango:DataOrigin`` | ||
| part which scope is the data located in this resource. | ||
| Returns | ||
| ------- | ||
| dict | ||
| Dictionary that can be used as input parameter for | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_query_origin` | ||
| """ | ||
| mapping = self._extract_query_origin() | ||
| for resource in self._votable.resources: | ||
| mapping = {**mapping, **self._extract_data_origin(resource)} | ||
| return mapping | ||
| def extract_coosys_mapping(self): | ||
| """ | ||
| Create a mapping dictionary for each ``COOSYS`` element found | ||
| in the first VOTable resource. | ||
| Returns | ||
| ------- | ||
| [dict] | ||
| Array of dictionaries which items can be used as input parameter for | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_simple_space_frame` | ||
| """ | ||
| mappings = [] | ||
| for resource in self._votable.resources: | ||
| for coordinate_system in resource.coordinate_systems: | ||
| mapping = {} | ||
| if not self._check_votable_head_element(coordinate_system.system): | ||
| logging.warning(f"Not valid COOSYS found: ignored in MIVOT: {coordinate_system}") | ||
| continue | ||
| mapping["spaceRefFrame"] = coordinate_system.system | ||
| if self._check_votable_head_element(coordinate_system.equinox): | ||
| mapping["equinox"] = coordinate_system.equinox | ||
| if self._check_votable_head_element(coordinate_system.epoch): | ||
| mapping["epoch"] = coordinate_system.epoch | ||
| mappings.append(mapping) | ||
| return mappings | ||
| def extract_timesys_mapping(self): | ||
| """ | ||
| Create a mapping dictionary for each ``TIMESYS`` element found | ||
| in the first VOTable resource. | ||
| .. note:: | ||
| the ``origin`` attribute is not supported yet | ||
| Returns | ||
| ------- | ||
| [dict] | ||
| Array of dictionaries which items can be used as input parameter for | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_simple_time_frame` | ||
| """ | ||
| mappings = [] | ||
| for resource in self._votable.resources: | ||
| for time_system in resource.time_systems: | ||
| mapping = {} | ||
| if not self._check_votable_head_element(time_system.timescale): | ||
| logging.warning(f"Not valid TIMESYS found: ignored in MIVOT: {time_system}") | ||
| continue | ||
| mapping["timescale"] = time_system.timescale | ||
| if self._check_votable_head_element(time_system.refposition): | ||
| mapping["refPosition"] = time_system.refposition | ||
| mappings.append(mapping) | ||
| return mappings | ||
| def extract_epochposition_mapping(self): | ||
| """ | ||
| Analyze the FIELD UCD-s to infer a data mapping to the EpochPosition class. | ||
| This mapping covers the 6 parameters with the Epoch and their errors. | ||
| The correlation part is not covered since there is no specific UCD for this. | ||
| The UCD-s accepted for each parameter are defined in `pyvo.mivot.glossary`. | ||
| The error classes are hard-coded as the most likely types. | ||
| - PErrorSym2D for 2D parameters | ||
| - PErrorSym1D for 1D parameters | ||
| Returns | ||
| ------- | ||
| (dict, dict) | ||
| A mapping proposal for the EpochPosiion + errors that can be used as input parameter | ||
| by :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_mango_epoch_position`. | ||
| """ | ||
| def _check_ucd(mapping_entry, ucd, mapping): | ||
| """ | ||
| Inner function checking that mapping_entry matches with ucd according to | ||
| `pyvo.mivot.glossary` | ||
| """ | ||
| if mapping_entry in mapping: | ||
| return False | ||
| dict_entry = getattr(EpochPositionAutoMapping, mapping_entry) | ||
| if isinstance(dict_entry, list): | ||
| return ucd in dict_entry | ||
| else: | ||
| return ucd.startswith(dict_entry) | ||
| def _check_obs_date(field): | ||
| """ check if the field can be interpreted as a value date time | ||
| This algorithm is a bit specific for Vizier CS | ||
| """ | ||
| xtype = field.xtype | ||
| unit = field.unit | ||
| representation = None | ||
| if xtype == "timestamp" or unit == "'Y:M:D'" or unit == "'Y-M-D'": | ||
| representation = "iso" | ||
| # let's assume that dates expressed as days are MJD | ||
| elif xtype == "mjd" or unit == "d": | ||
| representation = "mjd" | ||
| if representation is None and unit == "year": | ||
| representation = "year" | ||
| if representation is not None: | ||
| field_ref = field.ID if field.ID is not None else field.name | ||
| return {"dateTime": field_ref, "representation": representation} | ||
| return None | ||
| table = self._votable.get_first_table() | ||
| fields = table.fields | ||
| mapping = {} | ||
| error_mapping = {} | ||
| for field in fields: | ||
| ucd = field.ucd | ||
| for mapping_entry in Roles.EpochPosition: | ||
| if _check_ucd(mapping_entry, ucd, mapping) is True: | ||
| if mapping_entry == "obsDate": | ||
| if (obs_date_mapping := _check_obs_date(field)) is not None: | ||
| mapping[mapping_entry] = obs_date_mapping | ||
| else: | ||
| mapping[mapping_entry] = field.ID if field.ID is not None else field.name | ||
| # Once we got a parameter mapping, we look for its associated error | ||
| # This nested loop makes sure we never have error without value | ||
| for err_field in fields: | ||
| err_ucd = err_field.ucd | ||
| # We assume the error UCDs are the same the these of the | ||
| # related quantities but prefixed with "stat.error;" and without "meta.main" qualifier | ||
| if err_ucd == ("stat.error;" + ucd.replace(";meta.main", "")): | ||
| param_mapping = err_field.ID if err_field.ID is not None else err_field.name | ||
| if mapping_entry == "parallax": | ||
| error_mapping[mapping_entry] = {"class": "PErrorSym1D", | ||
| "sigma": param_mapping} | ||
| elif mapping_entry == "radialVelocity": | ||
| error_mapping[mapping_entry] = {"class": "PErrorSym1D", | ||
| "sigma": param_mapping} | ||
| elif mapping_entry == "longitude": | ||
| if "position" in error_mapping: | ||
| error_mapping["position"]["sigma1"] = param_mapping | ||
| else: | ||
| error_mapping["position"] = {"class": "PErrorSym2D", | ||
| "sigma1": param_mapping} | ||
| elif mapping_entry == "latitude": | ||
| if "position" in error_mapping: | ||
| error_mapping["position"]["sigma2"] = param_mapping | ||
| else: | ||
| error_mapping["position"] = {"class": "PErrorSym2D", | ||
| "sigma2": param_mapping} | ||
| elif mapping_entry == "pmLongitude": | ||
| if "properMotion" in error_mapping: | ||
| error_mapping["properMotion"]["sigma1"] = param_mapping | ||
| else: | ||
| error_mapping["properMotion"] = {"class": "PErrorSym2D", | ||
| "sigma1": param_mapping} | ||
| elif mapping_entry == "pmLatitude": | ||
| if "properMotion" in error_mapping: | ||
| error_mapping["properMotion"]["sigma2"] = param_mapping | ||
| else: | ||
| error_mapping["properMotion"] = {"class": "PErrorSym2D", | ||
| "sigma2": param_mapping} | ||
| return mapping, error_mapping |
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| MivotInstance is a simple API for building MIVOT instances step by step. | ||
| A MIVOT instance is a MIVOT serialisation of an object whose attributes are set | ||
| with column values or literals. | ||
| A MIVOT instance can contain ATTRIBUTEs elements, COLLECTIONs of elements, or other INSTANCEs. | ||
| The MIVOT INSTANCE structure is defined by the data model on which the data is mapped. | ||
| """ | ||
| from pyvo.utils.prototype import prototype_feature | ||
| from pyvo.mivot.utils.exceptions import MappingError | ||
| from pyvo.mivot.utils.mivot_utils import MivotUtils | ||
| __all__ = ["MivotInstance"] | ||
| @prototype_feature("MIVOT") | ||
| class MivotInstance: | ||
| """ | ||
| API for building <INSTANCE> elements of MIVOT annotation step by step. | ||
| This class provides methods for incremental construction of a MIVOT instance. | ||
| It builds <INSTANCE> elements that can contain <ATTRIBUTE>, <INSTANCE>, and <REFERENCE>. | ||
| Support for <COLLECTION> elements is not yet implemented. | ||
| The main features are: | ||
| - Model-agnostic: The implementation is independent of any specific data model. | ||
| - Syntax validation: Ensures basic MIVOT syntax rules are followed. | ||
| - Context-agnostic: Ignores context-dependent syntax rules. | ||
| attributes | ||
| ---------- | ||
| _dmtype : string | ||
| Instance type (class VO-DML ID) | ||
| _dmrole : string | ||
| Role played by the instance in the context where it is used | ||
| (given by the VO-DML serialization of the model) | ||
| _dmid : string | ||
| Free identifier of the instance | ||
| """ | ||
| def __init__(self, dmtype, *, dmrole=None, dmid=None): | ||
| """ | ||
| Parameters | ||
| ---------- | ||
| dmtype : str | ||
| dmtype of the INSTANCE (mandatory) | ||
| dmrole : str, optional | ||
| dmrole of the INSTANCE | ||
| dmid : str, optional | ||
| dmid of the INSTANCE | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``dmtype`` is not provided | ||
| """ | ||
| if not dmtype: | ||
| raise MappingError("Cannot build an instance without dmtype") | ||
| self._dmtype = dmtype | ||
| self._dmrole = dmrole | ||
| self._dmid = MivotUtils.format_dmid(dmid) | ||
| self._content = [] | ||
| @property | ||
| def dmid(self): | ||
| return self._dmid | ||
| def add_attribute(self, dmtype=None, dmrole=None, *, value=None, unit=None): | ||
| """ | ||
| Add an <ATTRIBUTE> element to the instance. | ||
| Parameters | ||
| ---------- | ||
| dmtype : str | ||
| dmtype of the ATTRIBUTE (mandatory) | ||
| dmrole : str | ||
| dmrole of the ATTRIBUTE (mandatory) | ||
| value : str or numerical, optional | ||
| ID of the column to set the attribute value. | ||
| If ref is a string starting with a * or is numerical, | ||
| it is considered as a value (* stripped) | ||
| as a ref otherwise | ||
| unit : str, optional | ||
| Unit of the attribute | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``dmtype`` or ``dmrole`` is not provided, or if both ``ref`` and ``value`` are not defined | ||
| """ | ||
| if not dmtype: | ||
| raise MappingError("Cannot add an attribute without dmtype") | ||
| if not dmrole: | ||
| raise MappingError("Cannot add an attribute without dmrole") | ||
| ref, literal = MivotUtils.get_ref_or_literal(value) | ||
| if not ref and not value: | ||
| raise MappingError("Cannot add an attribute without ref or value") | ||
| xml_string = f'<ATTRIBUTE dmtype="{dmtype}" dmrole="{dmrole}" ' | ||
| if unit and unit != "None": | ||
| xml_string += f'unit="{unit}" ' | ||
| if literal: | ||
| xml_string += f'value="{literal}" ' | ||
| else: | ||
| xml_string += f'ref="{ref}" ' | ||
| xml_string += " />" | ||
| self._content.append(xml_string) | ||
| def add_reference(self, dmrole=None, dmref=None): | ||
| """ | ||
| Add a <REFERENCE> element to the instance. | ||
| Parameters | ||
| ---------- | ||
| dmrole : str | ||
| dmrole of the REFERENCE (mandatory) | ||
| dmref : str | ||
| dmref of the REFERENCE (mandatory) | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``dmrole`` or ``dmref`` is not provided | ||
| """ | ||
| if not dmref: | ||
| raise MappingError("Cannot add a reference without dmref") | ||
| if not dmrole: | ||
| raise MappingError("Cannot add a reference without dmrole") | ||
| xml_string = f'<REFERENCE dmrole="{dmrole}" dmref="{dmref}" />' | ||
| self._content.append(xml_string) | ||
| def add_instance(self, mivot_instance): | ||
| """ | ||
| Add a nested <INSTANCE> element to the instance. | ||
| Parameters | ||
| ---------- | ||
| mivot_instance : MivotInstance | ||
| INSTANCE to be added | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``mivot_instance`` is not of type ``MivotInstance`` | ||
| """ | ||
| if not isinstance(mivot_instance, MivotInstance): | ||
| raise MappingError("Instance added must be of type MivotInstance") | ||
| self._content.append(mivot_instance.xml_string()) | ||
| def add_collection(self, dmrole, mivot_instances): | ||
| """ | ||
| to be documented | ||
| """ | ||
| dm_att = "" | ||
| if dmrole: | ||
| dm_att = f"dmrole=\"{dmrole}\"" | ||
| self._content.append(f'<COLLECTION {dm_att}>') | ||
| for mivot_instance in mivot_instances: | ||
| if isinstance(mivot_instance, MivotInstance): | ||
| self._content.append(mivot_instance.xml_string()) | ||
| else: | ||
| self._content.append(mivot_instance) | ||
| self._content.append("\n") | ||
| self._content.append("</COLLECTION>") | ||
| def xml_string(self): | ||
| """ | ||
| Build and serialize the <INSTANCE> element as a string. | ||
| Returns | ||
| ------- | ||
| str | ||
| The string representation of the <INSTANCE> element | ||
| """ | ||
| xml_string = f'<INSTANCE dmtype="{self._dmtype}" ' | ||
| if self._dmrole: | ||
| xml_string += f'dmrole="{self._dmrole}" ' | ||
| if self._dmid: | ||
| xml_string += f'dmid="{self._dmid}" ' | ||
| xml_string += ">\n" | ||
| for element in self._content: | ||
| xml_string += " " + element + "\n" | ||
| xml_string += "</INSTANCE>\n" | ||
| return xml_string |
| ''' | ||
| Created on 6 Feb 2025 | ||
| @author: laurentmichel | ||
| ''' | ||
| import logging | ||
| import re | ||
| import requests | ||
| # Use defusedxml only if already present in order to avoid a new dependency. | ||
| try: | ||
| from defusedxml import ElementTree as etree | ||
| # Element not implemented in recent versions of defusedxml | ||
| from xml.etree.ElementTree import Element | ||
| except ImportError: | ||
| from xml.etree import ElementTree as etree | ||
| from xml.etree.ElementTree import Element | ||
| from pyvo.mivot.utils.mivot_utils import MivotUtils | ||
| from pyvo.mivot.utils.xml_utils import XmlUtils | ||
| from pyvo.mivot.utils.xpath_utils import XPath | ||
| from pyvo.mivot.utils.vocabulary import Att, Ele | ||
| from pyvo.mivot.utils.exceptions import MappingError | ||
| from pyvo.mivot.writer.annotations import MivotAnnotations | ||
| from pyvo.mivot.writer.mango_object import MangoObject | ||
| from pyvo.mivot.writer.instance import MivotInstance | ||
| from pyvo.mivot.writer.header_mapper import HeaderMapper | ||
| from pyvo.mivot.glossary import ( | ||
| VodmlUrl, IvoaType, ModelPrefix, Url, CoordSystems) | ||
| class InstancesFromModels(object): | ||
| """ | ||
| **Top-level API class** that allows to create VOTable annotations with objects issued | ||
| from the Mango model and its imported classes. | ||
| The annotation structure is handled by the API based on mapping | ||
| rules provided by the user. | ||
| The classes currently supported are: | ||
| - Photometric Calibrations (PhotDM) | ||
| - Spatial and temporal coordinate systems (Coordinates DM) | ||
| - MangoObject (QueryOrigin, EpochPosition, Brightness and Color) | ||
| The mapping built by this API relates to the first table. | ||
| """ | ||
| def __init__(self, votable, *, dmid=None): | ||
| """ | ||
| Constructor parameters: | ||
| Parameters | ||
| ---------- | ||
| votable : astropy.io.votable.tree.VOTableFile | ||
| parsed votable to be annotated | ||
| dmid : string, optional (default is None) | ||
| Column identifier or value (is starts with ``*``) to be used as identifier of the | ||
| MangoObject mapping each data row | ||
| """ | ||
| self._votable = votable | ||
| self._table = votable.get_first_table() | ||
| self._header_mapper = HeaderMapper(self._votable) | ||
| self._mango_instance = MangoObject(self._table, dmid=dmid) | ||
| self._annotation = MivotAnnotations() | ||
| self._annotation.add_model("ivoa", | ||
| vodml_url=VodmlUrl.ivoa) | ||
| @property | ||
| def mivot_block(self): | ||
| return self._annotation.mivot_block | ||
| def _check_value_consistency(self, word, suggested_words): | ||
| """ | ||
| Utility checking that the word belongs to the list of suggested words | ||
| """ | ||
| if word.replace("*", "") not in suggested_words: | ||
| logging.warning("Ref frame %s is not in %s, make sure there is no typo", | ||
| word, suggested_words) | ||
| def extract_frames(self): | ||
| """ | ||
| Build space and time frames (``coords:SpaceSys`` and ``coords:TimeSys``) from | ||
| the INFO elements located in the header of the first VOTable resource. | ||
| The instances are added to the GLOBALS Mivot block. | ||
| .. note:: | ||
| The VOTable can host multiple instances of COOSYS or TIMESYS, but in | ||
| the current implementation, only the first one is taken | ||
| Returns | ||
| ------- | ||
| {"spaceSys": [{"dmid"}], "timeSys": [{"dmid"}]} | ||
| Dictionary of all dmid-s of the frames actually added to the annotations. | ||
| These dmid-s must be used by instances ATTRIBUTEs to their related frames. | ||
| This dictionary can be used ``frames`` parameter of ``add_mango_epoch_position`` | ||
| """ | ||
| ids = {"spaceSys": {}, "timeSys": {}} | ||
| # take the first coord system assuming it the most relevant | ||
| for coosys_mapping in self._header_mapper.extract_coosys_mapping(): | ||
| dmid = self.add_simple_space_frame(**coosys_mapping) | ||
| if "dmid" not in ids["spaceSys"]: | ||
| ids["spaceSys"]["dmid"] = dmid | ||
| for timesys_mapping in self._header_mapper.extract_timesys_mapping(): | ||
| dmid = self.add_simple_time_frame(**timesys_mapping) | ||
| if "dmid" not in ids["timeSys"]: | ||
| ids["timeSys"]["dmid"] = dmid | ||
| return ids | ||
| def extract_data_origin(self): | ||
| """ | ||
| Build a ``mango:QueryOrigin`` from | ||
| the INFO elements located in the VOTable header. | ||
| The instance is added to the GLOBALS Mivot block. | ||
| Returns | ||
| ------- | ||
| `MivotInstance` | ||
| The ``mango:QueryOrigin`` Mivot instance | ||
| """ | ||
| mapping = self._header_mapper.extract_origin_mapping() | ||
| return self.add_query_origin(mapping) | ||
| def extract_epoch_position_parameters(self): | ||
| """ | ||
| Build a dictionary with the 3 parameters required by | ||
| :py:meth:`pyvo.mivot.writer.InstancesFromModels.add_mango_epoch_position` | ||
| (frames, mapping, semantic). | ||
| - frames: references to the frames created from COOSYS/TIMSYS | ||
| (see :py:meth:`pyvo.mivot.writer.InstancesFromModels.extract_frames` | ||
| - mapping: inferred from the FIELD ucd-s | ||
| - semantics: hard-coded | ||
| This method does not add the ``EpochPosition`` property because the | ||
| mapping parameters often need first to be completed (or fixed) by hand. | ||
| This especially true for the correlations that cannot be automatically | ||
| detected in a generic way (no specific UCD) | ||
| .. code-block:: | ||
| epoch_position_mapping = builder.extract_epoch_position_parameters() | ||
| builder.add_mango_epoch_position(**epoch_position_mapping) | ||
| Returns | ||
| ------- | ||
| {"frames", "mapping", "semantics"} | ||
| Dictionary of mapping elements that can unpacked to feed ``add_mango_epoch_position()``. | ||
| """ | ||
| mapping, error_mapping = self._header_mapper.extract_epochposition_mapping() | ||
| mapping["errors"] = error_mapping | ||
| mapping["correlations"] = {} | ||
| semantics = {"description": "6 parameters position", | ||
| "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#astronomical-location", | ||
| "label": "Astronomical location"} | ||
| frames = self.extract_frames() | ||
| return {"frames": frames, "mapping": mapping, "semantics": semantics} | ||
| def add_photcal(self, filter_name): | ||
| """ | ||
| Add to the GLOBALS the requested photometric calibration as defined in PhotDM1.1 | ||
| The MIVOT serialization is provided by the SVO Filter Profile Service | ||
| (https://ui.adsabs.harvard.edu/abs/2020sea..confE.182R/abstract) | ||
| It is returned as one block containing the whole PhotCal instance. | ||
| The filter instance is extracted from the PhotCal object, where it is | ||
| replaced with a REFERENCE. | ||
| This makes the filter available as a GLOBALS to objects that need it. | ||
| - The dmid of the PhotCal is ``_photcal_DMID`` where DMID is the formatted | ||
| version of ``filter_name`` | ||
| (see `pyvo.mivot.utils.MivotUtils.format_dmid`). | ||
| - The dmid of the PhotFilter is ``_photfilter_DMID`` where DMID is the formatted | ||
| version of ``filter_name``. | ||
| Parameters | ||
| ---------- | ||
| filter_name : str | ||
| FPS identifier (SVO Photcal ID) of the request filter | ||
| Returns | ||
| ------- | ||
| (str, str) | ||
| dmids of photcal and filter instances | ||
| """ | ||
| response = requests.get(Url.FPS + filter_name) | ||
| if (http_code := response.status_code) != 200: | ||
| logging.error("FPS service error: %s", http_code) | ||
| return None, None | ||
| # get the MIVOT serialization of the requested Photcal (as a string) | ||
| # FPS returns bytes but that might change | ||
| fps_reponse = response.content | ||
| try: | ||
| fps_reponse = fps_reponse.decode('utf-8') | ||
| except (UnicodeDecodeError, AttributeError): | ||
| pass | ||
| # basic parsing of the response to check if an error has been returned | ||
| if "<INFO name=\"QUERY_STATUS\" value=\"ERROR\">" in fps_reponse: | ||
| message = re.search(r'<DESCRIPTION>(.*)</DESCRIPTION>', fps_reponse).group(1) | ||
| raise MappingError(f"FPS service error: {message}") | ||
| # set the identifiers that will be used for both PhotCal and PhotFilter | ||
| cal_id = MivotUtils.format_dmid(filter_name) | ||
| photcal_id = f"_photcal_{cal_id}" | ||
| filter_id = f"_photfilter_{cal_id}" | ||
| # skip if the same dmid is already recorded | ||
| if cal_id in self._annotation._dmids: | ||
| logging.warning("An instance with dmid=%s has already been stored in GLOBALS: skip", cal_id) | ||
| return photcal_id, filter_id | ||
| self._annotation._dmids.append(cal_id) | ||
| logging.info("%s PhotCal can be referred with dmref='%s'", cal_id, photcal_id) | ||
| # parse the PhotCal and extract the PhotFilter node | ||
| photcal_block = etree.fromstring(fps_reponse) | ||
| filter_block = XPath.x_path_contains(photcal_block, | ||
| ".//" + Ele.INSTANCE, | ||
| Att.dmtype, | ||
| "Phot:photometryFilter")[0] | ||
| # Tune the Photcal to be placed as a GLOBALS child (no role but an id) | ||
| # and remove the PhotFilter node which will be shifted at the GLOBALS level | ||
| del photcal_block.attrib["dmrole"] | ||
| photcal_block.set("dmid", photcal_id) | ||
| photcal_block.remove(filter_block) | ||
| # Tune the PhotFilter to be placed as GLOBALS child (no role but an id) | ||
| filter_role = filter_block.get("dmrole") | ||
| del filter_block.attrib["dmrole"] | ||
| filter_block.set("dmid", filter_id) | ||
| # Append a REFERENCE on the PhotFilter node to the PhotCal block | ||
| reference = Element("REFERENCE") | ||
| reference.set("dmrole", filter_role) | ||
| reference.set("dmref", filter_id) | ||
| photcal_block.append(reference) | ||
| self._annotation.add_model("ivoa", vodml_url=VodmlUrl.ivoa) | ||
| self._annotation.add_model("Phot", vodml_url=VodmlUrl.Phot) | ||
| # fix some FPS tweaks | ||
| photcal_block_string = XmlUtils.pretty_string(photcal_block, lshift=" ") | ||
| photcal_block_string = photcal_block_string.replace( | ||
| "<ATTRIBUTE dmrole=\"Phot:ZeroPoint.softeningParameter\" dmtype=\"ivoa:real\" value=\"\"/>", | ||
| "<!-- ATTRIBUTE dmrole=\"Phot:ZeroPoint.softeningParameter\"" | ||
| " dmtype=\"ivoa:real\" value=\"\"/ -->") | ||
| filter_block_string = XmlUtils.pretty_string(filter_block, lshift=" ") | ||
| filter_block_string = filter_block_string.replace("Phot:photometryFilter", "Phot:PhotometryFilter") | ||
| filter_block_string = filter_block_string.replace("Phot:PhotCal.photometryFilter.bandwidth", | ||
| "Phot:PhotometryFilter.bandwidth") | ||
| self._annotation.add_globals(photcal_block_string) | ||
| self._annotation.add_globals(filter_block_string) | ||
| return photcal_id, filter_id | ||
| def add_simple_space_frame(self, spaceRefFrame="ICRS", refPosition="BARYCENTER", | ||
| equinox=None, epoch=None): | ||
| """ | ||
| Adds a SpaceSys instance to the GLOBALS block as defined in the Coordinates | ||
| data model V1.0 (https://ivoa.net/documents/Coords/20221004/index.html). | ||
| Notes: | ||
| - This function implements only the most commonly used features. Custom reference positions | ||
| for TOPOCENTER frames are not supported. However, methods for implementing the missing | ||
| features can be derived from this code. | ||
| - A warning is emitted if either ``spaceRefFrame`` or ``refPosition`` | ||
| have unexpected values. | ||
| - No error is raised if the parameter values are inconsistent. | ||
| - The ``dmid`` of the time frame is built from ``spaceRefFrame``, | ||
| ``refrefPosition_position`` and ``equinox``. | ||
| Parameters | ||
| ---------- | ||
| spaceRefFrame : str, optional, default "ICRS" | ||
| The reference frame for the space frame. | ||
| refPosition : str, optional, default "BARYCENTER" | ||
| The reference position for the space frame. | ||
| equinox : str, optional, default None | ||
| The equinox for the reference frame, if applicable. | ||
| epoch : str, optional, default None | ||
| The epoch for the reference location, if applicable. | ||
| Returns | ||
| ------- | ||
| str | ||
| The actual dmid of the time frame INSTANCE | ||
| """ | ||
| # build the dmid | ||
| dmid = f"_spaceframe_{spaceRefFrame.replace('*', '')}" | ||
| if equinox: | ||
| dmid += f"_{equinox.replace('*', '')}" | ||
| if refPosition: | ||
| dmid += f"_{refPosition.replace('*', '')}" | ||
| # skip if the same dmid is already recorded | ||
| if dmid in self._annotation._dmids: | ||
| logging.warning("A spaceSys instance with dmid=%s has already been stored in GLOBALS: skip", | ||
| dmid) | ||
| return dmid | ||
| logging.info("spaceSys %s can be referred with dmref='%s'", spaceRefFrame, dmid) | ||
| self._annotation._dmids.append(dmid) | ||
| # add (or overwrite) used models | ||
| self._annotation.add_model(ModelPrefix.ivoa, vodml_url=VodmlUrl.ivoa) | ||
| self._annotation.add_model(ModelPrefix.coords, vodml_url=VodmlUrl.coords) | ||
| # check whether ref_frame and ref_position are set with appropriate values | ||
| self._check_value_consistency(spaceRefFrame, CoordSystems.space_frames) | ||
| self._check_value_consistency(refPosition, CoordSystems.ref_positions) | ||
| # Build the SpaceSys instance component by component | ||
| space_system_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:SpaceSys", | ||
| dmid=dmid) | ||
| # let's start with the space frame | ||
| space_frame_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:SpaceFrame", | ||
| dmrole=f"{ModelPrefix.coords}:PhysicalCoordSys.frame") | ||
| space_frame_instance.add_attribute(dmtype=IvoaType.string, | ||
| dmrole=f"{ModelPrefix.coords}:SpaceFrame.spaceRefFrame", | ||
| value=MivotUtils.as_literal(spaceRefFrame)) | ||
| if equinox is not None: | ||
| space_frame_instance.add_attribute(dmtype=f"{ModelPrefix.coords}:Epoch", | ||
| dmrole=f"{ModelPrefix.coords}:SpaceFrame.equinox", | ||
| value=MivotUtils.as_literal(equinox)) | ||
| # then let's build the reference position. | ||
| # The RefLocation type depends on the presence of an epoch (see coords DM) | ||
| if epoch is not None: | ||
| ref_position_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:CustomRefLocation", | ||
| dmrole=f"{ModelPrefix.coords}:SpaceFrame.refPosition") | ||
| ref_position_instance.add_attribute(dmtype=IvoaType.string, | ||
| dmrole=f"{ModelPrefix.coords}:CustomRefLocation.position", | ||
| value=MivotUtils.as_literal(refPosition)) | ||
| ref_position_instance.add_attribute(dmtype="coords:Epoch", | ||
| dmrole=f"{ModelPrefix.coords}:CustomRefLocation.epoch", | ||
| value=MivotUtils.as_literal(epoch)) | ||
| else: | ||
| ref_position_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:StdRefLocation", | ||
| dmrole=f"{ModelPrefix.coords}:SpaceFrame.refPosition") | ||
| ref_position_instance.add_attribute(dmtype=IvoaType.string, | ||
| dmrole=f"{ModelPrefix.coords}:StdRefLocation.position", | ||
| value=MivotUtils.as_literal(refPosition)) | ||
| # and pack everything | ||
| space_frame_instance.add_instance(ref_position_instance) | ||
| space_system_instance.add_instance(space_frame_instance) | ||
| # add the SpaceSys instance to the GLOBALS block | ||
| self._annotation.add_globals(space_system_instance) | ||
| return dmid | ||
| def add_simple_time_frame(self, timescale="TCB", *, refPosition="BARYCENTER"): | ||
| """ | ||
| Adds a TimeSys instance to the GLOBALS block as defined in the Coordinates | ||
| data model V1.0 (https://ivoa.net/documents/Coords/20221004/index.html). | ||
| Notes: | ||
| - This function implements only the most commonly used features. *Custom reference directions* | ||
| are not supported. However, methods for implementing missing features can be derived from | ||
| this code. | ||
| - A warning is emitted if either ``timescale`` or ``refPosition`` have unexpected values. | ||
| - No error is raised if the parameter values are inconsistent. | ||
| - The ``dmid`` of the time rame is built from ``timescale`` and ``refPosition``. | ||
| Parameters | ||
| ---------- | ||
| timescale : str, optional, default "TCB" | ||
| The reference frame for the time frame. | ||
| refPosition : str, optional, default "BARYCENTER" | ||
| The reference position for the time frame. | ||
| Returns | ||
| ------- | ||
| str | ||
| The actual dmid of the time frame INSTANCE | ||
| """ | ||
| # buikd the dmid | ||
| dmid = f"_timeframe_{timescale.replace('*', '')}" | ||
| if refPosition: | ||
| dmid += f"_{refPosition.replace('*', '')}" | ||
| dmid = MivotUtils.format_dmid(dmid) | ||
| # skip if the same dmid is already recorded | ||
| if dmid in self._annotation._dmids: | ||
| logging.warning("An timeSys instance with dmid=%s has already been stored in GLOBALS: skip", dmid) | ||
| return dmid | ||
| logging.info("timeSys %s can be referred with dmref='%s'", timescale, dmid) | ||
| self._annotation._dmids.append(dmid) | ||
| # add (or overwrite) used models | ||
| self._annotation.add_model(ModelPrefix.ivoa, vodml_url=VodmlUrl.ivoa) | ||
| self._annotation.add_model(ModelPrefix.coords, vodml_url=VodmlUrl.coords) | ||
| # check whether ref_frame and ref_position are set with appropriate values | ||
| self._check_value_consistency(timescale, CoordSystems.time_frames) | ||
| self._check_value_consistency(refPosition, CoordSystems.ref_positions) | ||
| # Build the TimeSys instance component by component | ||
| time_sys_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:TimeSys", | ||
| dmid=dmid) | ||
| # Let's start with the time frame | ||
| time_frame_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:TimeFrame", | ||
| dmrole=f"{ModelPrefix.coords}:PhysicalCoordSys.frame") | ||
| time_frame_instance.add_attribute(dmtype=IvoaType.string, | ||
| dmrole=f"{ModelPrefix.coords}:TimeFrame.timescale", | ||
| value=MivotUtils.as_literal(timescale)) | ||
| # Then let's build the reference position | ||
| ref_position_instance = MivotInstance(dmtype=f"{ModelPrefix.coords}:StdRefLocation", | ||
| dmrole=f"{ModelPrefix.coords}:TimeFrame.refPosition") | ||
| ref_position_instance.add_attribute(dmtype=IvoaType.string, | ||
| dmrole=f"{ModelPrefix.coords}:StdRefLocation.position", | ||
| value=MivotUtils.as_literal(refPosition)) | ||
| # pack everything | ||
| time_frame_instance.add_instance(ref_position_instance) | ||
| time_sys_instance.add_instance(time_frame_instance) | ||
| # add the TimeSys instance to the GLOBALS block | ||
| self._annotation.add_globals(time_sys_instance) | ||
| return dmid | ||
| def add_mango_brightness(self, *, photcal_id=None, mapping={}, semantics={}): | ||
| """ | ||
| Add a Mango ``Brightness`` instance to the current `MangoObject` with the specified | ||
| photometric calibration, using the mapping parameter to associate VOtable data with it. | ||
| This method acts as a front-end for `pyvo.mivot.writer.MangoObject` logic. | ||
| Parameters | ||
| ---------- | ||
| photcal_id : string, optional (default is None) | ||
| Filter profile service (http://svo2.cab.inta-csic.es/theory/fps/} identifier | ||
| of the desired photometric calibration. It is made of the filter identifier | ||
| followed by the photometric system (e.g. GAIA/GAIA3.Grvs/AB) | ||
| mapping : dict, optional (default to an empty dictionary ({}) | ||
| A dictionary defining the mapping of values. It includes: | ||
| - mapping of the brightness value | ||
| - one separate block for the error specification | ||
| semantics : dict, optional (default to an empty dictionary ({}) | ||
| A dictionary specifying semantic details to be added to the Mango property. | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The Mango property | ||
| Notes | ||
| ----- | ||
| The mapping example below maps the data of the GaiaD3 table that can be found | ||
| in the test suite. Notice that the (fake) error bounds are given as literalS. | ||
| .. code-block:: python | ||
| photcal_id="GAIA/GAIA3.Grvs/AB" | ||
| mapping={"value": "GRVSmag", | ||
| "error": { "class": "PErrorAsym1D", "low": 1, "high": 3} | ||
| } | ||
| semantics={"description": "Grvs magnitude", | ||
| "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#magnitude", | ||
| "label": "magnitude"} | ||
| builder = InstancesFromModels(votable, dmid="DR3Name") | ||
| builder.add_mango_magnitude(photcal_id=photcal_id, mapping=mapping, semantics=semantics) | ||
| """ | ||
| # make sure MANGO is mentioned in <MODELS> | ||
| self._annotation.add_model(ModelPrefix.mango, vodml_url=VodmlUrl.mango) | ||
| # Add the photometric calibration instance in <GLOBALS> | ||
| photcal_id, _ = self.add_photcal(photcal_id) | ||
| # Add the brightness property to the MANGO instance | ||
| return self._mango_instance.add_brightness_property(photcal_id, | ||
| mapping, | ||
| semantics=semantics) | ||
| def add_mango_color(self, *, filter_ids={}, mapping={}, semantics={}): | ||
| """ | ||
| Add a Mango ``Color`` instance to the current `MangoObject` with the specified | ||
| low and high filters, using the mapping parameter to associate VOtable data with it. | ||
| This method acts as a front-end for `pyvo.mivot.writer.MangoObject` logic. | ||
| Parameters | ||
| ---------- | ||
| filter_ids : string, optional (default to an empty dictionary {}) | ||
| Filter profile service (http://svo2.cab.inta-csic.es/theory/fps/} identifiers | ||
| of the high and low photometric calibrations that contain the desired filters. | ||
| Identifiers are made of the filter identifier | ||
| followed by the photometric system (e.g. GAIA/GAIA3.Grvs/AB). | ||
| mapping : dict, optional (default to an empty dictionary ({}) | ||
| A dictionary defining the mapping of values. It includes: | ||
| - The mapping of the color value and the color definition (ColorIndex or | ||
| HardnessRatio). | ||
| - One separate block for the error specification. | ||
| semantics : dict, optional (default to an empty dictionary {}) | ||
| A dictionary specifying semantic details to be added to the Mango property. | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The Mango property | ||
| Notes | ||
| ----- | ||
| The mapping example below maps the data of the GaiaD3 table that can be found | ||
| in the test suite. | ||
| The (fake) color value is given as a literal, it does not refer to any table column. | ||
| .. code-block:: python | ||
| filter_ids={"low": "GAIA/GAIA3.Grp/AB", "high": "GAIA/GAIA3.Grvs/AB"} | ||
| mapping={"value": 0.08, "definition": "ColorIndex", | ||
| "error": { "class": "PErrorAsym1D", "low": 0.01, "high": 0.02} | ||
| } | ||
| semantics={"description": "Fake color index", | ||
| "uri": "http://astrothesaurus.org/uat/1553", | ||
| "label": "Spectral index"} | ||
| builder = InstancesFromModels(votable, dmid="DR3Name") | ||
| builder.add_mango_color(filter_ids=filter_ids, mapping=mapping, semantics=semantics) | ||
| """ | ||
| self._annotation.add_model(ModelPrefix.mango, vodml_url=VodmlUrl.mango) | ||
| filter_low_name = filter_ids["low"] | ||
| filter_high_name = filter_ids["high"] | ||
| _, filter_low_id = self.add_photcal(filter_low_name) | ||
| _, filter_high_id = self.add_photcal(filter_high_name) | ||
| return self._mango_instance.add_color_instance(filter_low_id, | ||
| filter_high_id, | ||
| mapping, | ||
| semantics=semantics) | ||
| def add_mango_epoch_position(self, *, frames={}, mapping={}, semantics={}): | ||
| """ | ||
| Add a Mango ``EpochPosition`` instance to the current `MangoObject` with the specified | ||
| frames and semantics, using the mapping parameter to associate VOtable data with it. | ||
| This method acts as a front-end for `pyvo.mivot.writer.MangoObject` logic. | ||
| Parameters | ||
| ---------- | ||
| frames : dict, optional (default to an empty dictionary {}) | ||
| A dictionary specifying the frames (space and time coordinate systems) to be used. | ||
| Frames parameters are global, they cannot refer to table columns. | ||
| If a frame description contains the "dmid" key, that value will be used as an identifier | ||
| an already installed frame (e.g. with ``extract_frames()``). Otherwise the content of | ||
| the frame description is meant to be used in input parameter | ||
| for ``add_simple_(space)time_frame()`` | ||
| mapping : dict, optional (default to an empty dictionary {}) | ||
| A dictionary defining the mapping of values. It includes: | ||
| - A flat list for position parameters. | ||
| - Two separate blocks for correlations and error specifications. | ||
| semantics : dict, optional (default to an empty dictionary {}) | ||
| A dictionary specifying semantic details to be added to the Mango property. | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The Mango property | ||
| Notes | ||
| ----- | ||
| The mapping example below maps the data of the GaiaD3 table that can be found in the test suite. | ||
| .. code-block:: python | ||
| 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", | ||
| "correlations": {"isCovariance": True, "longitudeLatitude": "RADEcor", | ||
| "latitudePmLongitude": "DEpmRAcor", "latitudePmLatitude": "DEpmDEcor", | ||
| "longitudePmLongitude": "RApmRAcor", "longitudePmLatitude": "RApmDEcor", | ||
| "longitudeParallax": "RAPlxcor", "latitudeParallax": "DEPlxcor", | ||
| "pmLongitudeParallax": "PlxpmRAcor", "pmLatitudeParallax": "PlxpmDEcor", | ||
| }, | ||
| "errors": { "position": { "class": "PErrorSym2D", "sigma1": "e_RA_ICRS", | ||
| "sigma2": "e_DE_ICRS"}, | ||
| "properMotion": { "class": "PErrorSym2D", "sigma1": "e_pmRA", | ||
| "sigma2": "e_pmDE"}, | ||
| "parallax": { "class": "PErrorSym1D", "sigma": "e_Plx"}, | ||
| "radialVelocity": { "class": "PErrorSym1D", "sigma": "e_RV"} | ||
| } | ||
| } | ||
| semantics={"description": "6 parameters position", | ||
| "uri": "https://www.ivoa.net/rdf/uat/2024-06-25/uat.html#astronomical-location", | ||
| "label": "Astronomical location"} | ||
| builder = InstancesFromModels(votable, dmid="DR3Name") | ||
| builder.add_mango_epoch_position(frames=frames, mapping=mapping, semantics=semantics) | ||
| """ | ||
| self._annotation.add_model(ModelPrefix.mango, vodml_url=VodmlUrl.mango) | ||
| space_frame_id = "" | ||
| if "spaceSys" in frames and frames["spaceSys"]: | ||
| if "dmid" in frames["spaceSys"]: | ||
| space_frame_id = frames["spaceSys"]["dmid"] | ||
| else: | ||
| space_frame_id = self.add_simple_space_frame(*frames["spaceSys"]) | ||
| time_frame_id = "" | ||
| if "timeSys" in frames and frames["timeSys"]: | ||
| if "dmid" in frames["timeSys"]: | ||
| time_frame_id = frames["timeSys"]["dmid"] | ||
| else: | ||
| time_frame_id = self.add_simple_time_frame(**frames["timeSys"]) | ||
| return self._mango_instance.add_epoch_position(space_frame_id, time_frame_id, mapping, | ||
| semantics) | ||
| def add_query_origin(self, mapping={}): | ||
| """ | ||
| Add the Mango ``QueryOrigin`` instance to the current `MangoObject`. | ||
| This method acts as a front-end for `pyvo.mivot.writer.MangoObject` logic. | ||
| Parameters | ||
| ---------- | ||
| mapping : dict, optional (default to an empty dictionary {}) | ||
| A dictionary defining the QueryOrigin fields. Mapped fields are global, | ||
| they cannot refer to table columns | ||
| Returns | ||
| ------- | ||
| `MivotInstance` | ||
| Notes | ||
| ----- | ||
| The partial mapping example below maps a fake QueryOrigin. A complete (long) example based on GaiaD3 | ||
| can be found in the test suite. | ||
| .. code-block:: python | ||
| builder = InstancesFromModels(votable, dmid="DR3Name") | ||
| builder.add_query_origin( | ||
| { | ||
| "service_protocol": "ivo://ivoa.net/std/ConeSearch/v1.03", | ||
| "request_date": "2025-04-07T12:06:32", | ||
| "request": ( | ||
| "https://cdsarc.cds.unistra.fr/beta/viz-bin/mivotconesearch" | ||
| "/I/329/urat1?RA=52.26708&DEC=59.94027&SR=0.05" | ||
| ), | ||
| "contact": "cds-question@unistra.fr", | ||
| "server_software": "7.4.6", | ||
| "publisher": "CDS", | ||
| "dataOrigin": [ | ||
| { | ||
| "ivoid": "ivo://cds.vizier/i/329", | ||
| "creators": ["Zacharias N."], | ||
| "cites": "bibcode:2015AJ....150..101Z", | ||
| "original_date": "2015", | ||
| "reference_url": "https://cdsarc.cds.unistra.fr/viz-bin/cat/I/329", | ||
| "rights_uri": "https://cds.unistra.fr/vizier-org/licences_vizier.html", | ||
| "articles": [{"editor": "Astronomical Journal (AAS)"}], | ||
| } | ||
| ], | ||
| } | ||
| ) | ||
| """ | ||
| self._annotation.add_model(ModelPrefix.mango, vodml_url=VodmlUrl.mango) | ||
| query_origin_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:origin.QueryOrigin", | ||
| dmid="_origin") | ||
| MivotUtils.populate_instance(query_origin_instance, "QueryOrigin", mapping, self._table, | ||
| IvoaType.string, as_literals=True, package="origin") | ||
| if "dataOrigin" in mapping: | ||
| origins = [] | ||
| data_origin_mappings = mapping["dataOrigin"] | ||
| for data_origin_mapping in data_origin_mappings: | ||
| data_origin_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:origin.DataOrigin") | ||
| MivotUtils.populate_instance(data_origin_instance, "DataOrigin", | ||
| data_origin_mapping, self._table, | ||
| IvoaType.string, as_literals=True, package="origin") | ||
| if "articles" in data_origin_mapping: | ||
| articles = [] | ||
| for art_mapping in data_origin_mapping["articles"]: | ||
| art_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:origin.Article") | ||
| MivotUtils.populate_instance(art_instance, "Article", art_mapping, | ||
| self._table, IvoaType.string, | ||
| as_literals=True, package="origin") | ||
| articles.append(art_instance) | ||
| data_origin_instance.add_collection(f"{ModelPrefix.mango}:origin.DataOrigin.articles", | ||
| articles) | ||
| if "creators" in data_origin_mapping: | ||
| creators = [] | ||
| for art_mapping in data_origin_mapping["creators"]: | ||
| creators.append(f"<ATTRIBUTE dmtype=\"ivoa:string\" value=\"{art_mapping}\" />") | ||
| data_origin_instance.add_collection(f"{ModelPrefix.mango}:origin.DataOrigin.creators", | ||
| creators) | ||
| origins.append(data_origin_instance) | ||
| query_origin_instance.add_collection(f"{ModelPrefix.mango}:origin.QueryOrigin.dataOrigin", | ||
| origins) | ||
| self._annotation.add_globals(query_origin_instance) | ||
| self._annotation._dmids.append("_origin") | ||
| return query_origin_instance | ||
| def pack_into_votable(self, *, report_msg="", sparse=False): | ||
| """ | ||
| Pack all mapped objects in the annotation block and put it in the VOTable. | ||
| Parameters | ||
| ---------- | ||
| report_msg: string, optional (default to an empty string) | ||
| Content of the REPORT Mivot tag | ||
| sparse: boolean, optional (default to False) | ||
| If True, all properties are added in a independent way to the the TEMPLATES. | ||
| They are packed in a MangoObject otherwise. | ||
| """ | ||
| self._annotation.set_report(True, report_msg) | ||
| if sparse is True: | ||
| for prop in self._mango_instance.mango_properties: | ||
| # Add each individual property to the TEMPLATES block | ||
| self._annotation.add_templates(prop.xml_string()) | ||
| else: | ||
| # Pack the MangoObject and put it in the TEMPLATES | ||
| self._annotation.add_templates(self._mango_instance.get_mango_object( | ||
| with_origin=("_origin" in self._annotation._dmids))) | ||
| self._annotation.build_mivot_block() | ||
| self._annotation.insert_into_votable(self._votable, override=True) |
| ''' | ||
| Created on 22 Jan 2025 | ||
| @author: laurentmichel | ||
| ''' | ||
| from pyvo.mivot.utils.exceptions import MappingError | ||
| from pyvo.mivot.utils.mivot_utils import MivotUtils | ||
| from pyvo.mivot.writer.instance import MivotInstance | ||
| from pyvo.mivot.glossary import ( | ||
| IvoaType, ModelPrefix, Roles, CoordSystems) | ||
| class Property(MivotInstance): | ||
| """ | ||
| Class representing one property of a MangoInstance. MangoInstance property | ||
| instances are `pyvo.mivot.writer.MivotInstance` augmented with a semantics block. | ||
| """ | ||
| def __init__(self, dmtype=None, *, dmrole=None, dmid=None, semantics={}): | ||
| """ | ||
| Parameters | ||
| ---------- | ||
| dmtype : str | ||
| dmtype of the INSTANCE (mandatory) | ||
| dmrole : str, optional (default as None) | ||
| dmrole of the INSTANCE | ||
| dmid : str, optional (default as None) | ||
| dmid of the INSTANCE | ||
| semantics : dict, optional (default as {}) | ||
| Mapping of the semantic block (supported key: descripton, uri, label) | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If ``dmtype`` is not provided | ||
| """ | ||
| super().__init__(dmtype, dmrole=dmrole, dmid=dmid) | ||
| if "description" in semantics: | ||
| # we assume the description as always being a literal | ||
| self.add_attribute(dmtype="ivoa:string", | ||
| dmrole="mango:Property.description", | ||
| value=f"*{semantics['description']}") | ||
| if "uri" in semantics or "label" in semantics: | ||
| semantics_instance = MivotInstance(dmtype="mango:VocabularyTerm", | ||
| dmrole="mango:Property.semantics") | ||
| if "uri" in semantics: | ||
| semantics_instance.add_attribute(dmtype="ivoa:string", | ||
| dmrole="mango:VocabularyTerm.uri", | ||
| value=f"*{semantics['uri']}") | ||
| if "label" in semantics: | ||
| semantics_instance.add_attribute(dmtype="ivoa:string", dmrole="mango:VocabularyTerm.label", | ||
| value=f"*{semantics['label']}") | ||
| self.add_instance(semantics_instance) | ||
| class MangoObject(object): | ||
| """ | ||
| This class handles all the components of a MangoObject (properties, origin, instance identifier). | ||
| It is meant to be used by `pyvo.mivot.writer.InstancesFromModels` but not by end users. | ||
| - There is one specific method for each supported property (EpochPosition, photometry and QueryOrigin). | ||
| - The internal structure of the classes is hard-coded in the class logic. | ||
| """ | ||
| def __init__(self, table, *, dmid=None): | ||
| ''' | ||
| Constructor parameters: | ||
| parameters | ||
| ---------- | ||
| table : astropy.io.votable.tree.TableElement | ||
| VOTable table which data is mapped on Mango | ||
| dmid: stringn optional (default as None) | ||
| Reference of the column to be used as a MangoObject identifier | ||
| ''' | ||
| self._table = table | ||
| self._properties = [] | ||
| self._dmid = dmid | ||
| def _get_error_instance(self, class_name, dmrole, mapping): | ||
| """ | ||
| Private method building and returning an Mango error instance | ||
| Returns: MivotInstance | ||
| """ | ||
| prop_err_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:error.{class_name}", | ||
| dmrole=dmrole) | ||
| MivotUtils.populate_instance(prop_err_instance, class_name, mapping, | ||
| self._table, IvoaType.RealQuantity, package="error") | ||
| return prop_err_instance | ||
| def _add_epoch_position_correlations(self, **correlations): | ||
| """ | ||
| Private method building and returning the correlation block of the EpocPosition object. | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The EpochPosition correlations component | ||
| """ | ||
| epc_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:EpochPositionCorrelations", | ||
| dmrole=f"{ModelPrefix.mango}:EpochPosition.correlations") | ||
| MivotUtils.populate_instance(epc_instance, "EpochPositionCorrelations", | ||
| correlations, self._table, IvoaType.real) | ||
| return epc_instance | ||
| def _add_epoch_position_errors(self, **errors): | ||
| """ | ||
| Private method building and returning the error block of the EpocPosition object. | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The EpochPosition error instance | ||
| """ | ||
| err_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:EpochPositionErrors", | ||
| dmrole=f"{ModelPrefix.mango}:EpochPosition.errors") | ||
| for role, mapping in errors.items(): | ||
| error_class = mapping["class"] | ||
| if (role in Roles.EpochPositionErrors | ||
| and error_class in ["PErrorSym2D", "PErrorSym1D", "PErrorAsym1D"]): | ||
| err_instance.add_instance( | ||
| self._get_error_instance(error_class, | ||
| f"{ModelPrefix.mango}:EpochPositionErrors.{role}", | ||
| 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``. | ||
| Both mapping and semantics arguments inherit from | ||
| `pyvo.mivot.writer.InstancesFromModels.add_mango_epoch_position`. | ||
| Parameters | ||
| ---------- | ||
| space_frame_id : string | ||
| Identifier (dmid) of space system INSTANCE located in the GLOBALS | ||
| time_frame_id : string | ||
| Identifier (dmid) of time system INSTANCE located in the GLOBALS | ||
| mapping : dict | ||
| Mapping of the EpochPosition fields | ||
| semantics : dict | ||
| Mapping of the MangoObject property | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The EpochPosition instance | ||
| """ | ||
| ep_instance = Property(dmtype=f"{ModelPrefix.mango}:EpochPosition", | ||
| semantics=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 "correlations" in mapping: | ||
| ep_instance.add_instance(self._add_epoch_position_correlations(**mapping["correlations"])) | ||
| if "errors" in mapping: | ||
| ep_instance.add_instance(self._add_epoch_position_errors(**mapping["errors"])) | ||
| if space_frame_id: | ||
| ep_instance.add_reference(dmrole=f"{ModelPrefix.mango}:EpochPosition.spaceSys", | ||
| dmref=space_frame_id) | ||
| if time_frame_id: | ||
| ep_instance.add_reference(dmrole=f"{ModelPrefix.mango}:EpochPosition.timeSys", | ||
| dmref=time_frame_id) | ||
| self._properties.append(ep_instance) | ||
| return ep_instance | ||
| def add_brightness_property(self, filter_id, mapping, semantics={}): | ||
| """ | ||
| Add a ``Brightness`` instance to the properties of the current ``MangoObject``. | ||
| Both mapping and semantics arguments inherit from | ||
| `pyvo.mivot.writer.InstancesFromModels.add_mango_brightness`. | ||
| Parameters | ||
| ---------- | ||
| filter_id : string | ||
| Identifier (dmid) of the PhotCal INSTANCE located in the GLOBALS | ||
| mapping : dict | ||
| Mapping of the EpochPosition fields | ||
| semantics : dict | ||
| Mapping of the MangoObject property | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The Brightness instance | ||
| """ | ||
| # create the MIVOT instance mapping the MANGO property | ||
| mag_instance = Property(dmtype=f"{ModelPrefix.mango}:Brightness", | ||
| semantics=semantics) | ||
| # set MANGO property attribute | ||
| MivotUtils.populate_instance(mag_instance, "PhotometricProperty", | ||
| mapping, self._table, IvoaType.RealQuantity) | ||
| # build the error instance if it is mapped | ||
| if "error" in mapping: | ||
| error_mapping = mapping["error"] | ||
| error_class = error_mapping["class"] | ||
| mag_instance.add_instance( | ||
| self._get_error_instance(error_class, | ||
| f"{ModelPrefix.mango}:PhotometricProperty.error", | ||
| error_mapping)) | ||
| # add MIVOT reference to the photometric calibration instance | ||
| mag_instance.add_reference(dmrole=f"{ModelPrefix.mango}:Brightness.photCal", dmref=filter_id) | ||
| self._properties.append(mag_instance) | ||
| return mag_instance | ||
| def add_color_instance(self, filter_low_id, filter_high_id, mapping, semantics={}): | ||
| """ | ||
| Add an ``Color`` instance to the properties of the current ``MangoObject``. | ||
| Both mapping and semantics arguments inherit from | ||
| `pyvo.mivot.writer.InstancesFromModels.add_mango_color`. | ||
| Parameters | ||
| ---------- | ||
| filter_low_id : string | ||
| Identifier (dmid) of the low energy Photfilter INSTANCE located in the GLOBALS | ||
| filter_high_id : string | ||
| Identifier (dmid) of the high energy Photfilter INSTANCE located in the GLOBALS | ||
| mapping : dict | ||
| Mapping of the EpochPosition fields | ||
| semantics : dict | ||
| Mapping of the MangoObject property | ||
| Returns | ||
| ------- | ||
| `Property` | ||
| The Color instance | ||
| """ | ||
| error_mapping = mapping["error"] | ||
| mag_instance = Property(dmtype=f"{ModelPrefix.mango}:Color", | ||
| semantics=semantics) | ||
| coldef_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:ColorDef", | ||
| dmrole=f"{ModelPrefix.mango}:Color.colorDef") | ||
| mapped_roles = MivotUtils._valid_mapped_dmroles(mapping.items(), "Color") | ||
| def_found = False | ||
| for dmrole, column in mapped_roles: | ||
| if dmrole.endswith("definition"): | ||
| def_found = True | ||
| coldef_instance.add_attribute(dmtype="mango:ColorDefinition", | ||
| dmrole="mango:ColorDef.definition", | ||
| value=f"*{column}") | ||
| if not def_found: | ||
| raise MappingError("Missing color definition") | ||
| mapping.pop("definition") | ||
| MivotUtils.populate_instance(mag_instance, "PhotometricProperty", mapping, | ||
| self._table, IvoaType.RealQuantity) | ||
| coldef_instance.add_reference(dmrole=f"{ModelPrefix.mango}:ColorDef.low", | ||
| dmref=filter_low_id) | ||
| coldef_instance.add_reference(dmrole=f"{ModelPrefix.mango}:ColorDef.high", | ||
| dmref=filter_high_id) | ||
| error_class = error_mapping["class"] | ||
| mag_instance.add_instance(self._get_error_instance(error_class, | ||
| f"{ModelPrefix.mango}:PhotometricProperty.error", | ||
| error_mapping)) | ||
| mag_instance.add_instance(coldef_instance) | ||
| self._properties.append(mag_instance) | ||
| return mag_instance | ||
| def get_mango_object(self, with_origin=False): | ||
| """ | ||
| Make and return the XML serialization of the MangoObject. | ||
| Parameters | ||
| ---------- | ||
| with_origin : bool | ||
| Ask for adding a reference (_origin) to the query origin possibly located in the GLOBALS | ||
| Returns | ||
| ------- | ||
| string | ||
| The XML serialization of the MangoObject | ||
| """ | ||
| mango_object = MivotInstance(dmtype="mango:MangoObject", dmid=self._dmid) | ||
| if self._dmid: | ||
| ref, value = MivotUtils.get_ref_or_literal(self._dmid) | ||
| att_value = ref if ref else value | ||
| mango_object.add_attribute(dmrole="mango:MangoObject.identifier", | ||
| dmtype=IvoaType.string, | ||
| value=att_value) | ||
| if with_origin: | ||
| mango_object.add_reference("mango:MangoObject.queryOrigin", "_origin") | ||
| m_properties = [] | ||
| for prop in self._properties: | ||
| m_properties.append(prop.xml_string()) | ||
| mango_object.add_collection("mango:MangoObject.propertyDock", m_properties) | ||
| return mango_object |
| <!-- XML Schema for the VODML lite mapping L. Michel 06/2020 --> | ||
| <!-- MIVOT schema for the record --> | ||
| <!-- GL 2021-07-23: Refactoring towards using type definitions rather than | ||
| global elements. Following VOTable v 1.11 refactoring from 23-May-2006 LM | ||
| 2021-08-25: add VOtable import, prefix prefixes with dm-mapping --> | ||
| <!-- ======================= --> | ||
| <!-- XSD sample http://users.polytech.unice.fr/~pfz/LANGDOC/COURS/EXEMPLES/XSD_DXS/chapter14.html --> | ||
| <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" version="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ivoa.net/xml/mivot" xmlns:dm-mapping="http://www.ivoa.net/xml/mivot"> | ||
| <!-- Required to validate mapping block within a VOTable (LM 08/2021) --> | ||
| <xs:import namespace="http://www.ivoa.net/xml/VOTable/v1.3" schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3"/> | ||
| <xs:import namespace="http://www.ivoa.net/xml/VOTable/v1.2" schemaLocation="http://www.ivoa.net/xml/VOTable/v1.2"/> | ||
| <xs:import namespace="http://www.ivoa.net/xml/VOTable/v1.1" schemaLocation="http://www.ivoa.net/xml/VOTable/v1.1"/> | ||
| <!-- Top level structure of the mapping block --> | ||
| <xs:element name="VODML"> | ||
| <xs:complexType> | ||
| <xs:sequence> | ||
| <xs:element name="REPORT" type="dm-mapping:Report" minOccurs="0" maxOccurs="1"/> | ||
| <xs:element name="MODEL" type="dm-mapping:Model" minOccurs="0" maxOccurs="unbounded"/> | ||
| <xs:element name="GLOBALS" type="dm-mapping:Globals" minOccurs="0" maxOccurs="1"/> | ||
| <xs:element name="TEMPLATES" type="dm-mapping:Templates" minOccurs="0" maxOccurs="unbounded"/> | ||
| </xs:sequence> | ||
| <!-- MD proposal | ||
| <xs:assert | ||
| test="if (dm-mapping:REPORT[@status] = 'OK') then (count(dm-mapping:MODEL) > 0) else true()" /> | ||
| <xs:assert | ||
| test="if (dm-mapping:REPORT[@status] = 'FAILED') then (count(dm-mapping:MODEL) >= 0) else true()" /> | ||
| <xs:assert | ||
| test="if (count(dm-mapping:MODEL) = 0) then (count(dm-mapping:REPORT) = 1) else true()" /> | ||
| <xs:assert | ||
| test="if (count(dm-mapping:REPORT) = 0) then (count(dm-mapping:MODEL) > 0) else true()" /> | ||
| --> | ||
| </xs:complexType> | ||
| <!-- Make sure dmid is unique within the mapping block --> | ||
| <xs:unique name="Uniquedmid"> | ||
| <xs:selector xpath=".//*"/> | ||
| <xs:field xpath="@dmid"/> | ||
| </xs:unique> | ||
| </xs:element> | ||
| <!-- Annotation process report--> | ||
| <xs:complexType name="Report" mixed="true"> | ||
| <xs:attribute name="status" type="xs:string" use="required"/> | ||
| <xs:assert test="@status = 'OK' or @status = 'FAILED'"/> | ||
| </xs:complexType> | ||
| <!-- Declaration of one used model --> | ||
| <xs:complexType name="Model"> | ||
| <xs:attribute name="name" type="xs:string"/> | ||
| <xs:attribute name="url" type="xs:anyURI"/> | ||
| <xs:assert test="@name != ''"/> | ||
| <xs:assert test="if (@url) then (@url != '') else true() "/> | ||
| </xs:complexType> | ||
| <!-- Mapping of the data that have a global scope (e.g. frames) --> | ||
| <xs:complexType name="Globals"> | ||
| <xs:all> | ||
| <xs:element name="INSTANCE" type="dm-mapping:Instance" minOccurs="0" maxOccurs="unbounded"/> | ||
| <xs:element name="COLLECTION" type="dm-mapping:Collection" minOccurs="0" maxOccurs="unbounded"/> | ||
| </xs:all> | ||
| <xs:assert test="count (dm-mapping:INSTANCE[@dmrole != '']) eq 0"/> | ||
| <xs:assert test="count (dm-mapping:COLLECTION[@dmrole != '']) eq 0"/> | ||
| <xs:assert test="every $child in ./dm-mapping:COLLECTION satisfies $child/@dmid != '' "/> | ||
| <xs:assert test="every $child in ./dm-mapping:COLLECTION satisfies ( every $grandchild in $child/dm-mapping:INSTANCE satisfies ( count($grandchild/dm-mapping:PRIMARY_KEY) gt 0 ) )"/> | ||
| <xs:assert test="every $child in ./dm-mapping:COLLECTION satisfies ( every $grandchild in $child/dm-mapping:JOIN satisfies (count($grandchild/@dmref) or count($grandchild/@sourceref)))"/> | ||
| <xs:assert test="every $child in ./dm-mapping:COLLECTION satisfies count($child/dm-mapping:ATTRIBUTE) = 0"/> | ||
| <!-- | ||
| <xs:assert | ||
| test="every $child in .//dm-mapping:ATTRIBUTE satisfies (not($child/@ref) or $child/@ref = '')" /> | ||
| --> | ||
| </xs:complexType> | ||
| <!-- Mapping of the data contained in a particular table --> | ||
| <xs:complexType name="Templates"> | ||
| <xs:sequence> | ||
| <xs:element name="WHERE" type="dm-mapping:Where" minOccurs="0" maxOccurs="unbounded"/> | ||
| <xs:element name="INSTANCE" type="dm-mapping:Instance" minOccurs="1" maxOccurs="unbounded"/> | ||
| </xs:sequence> | ||
| <xs:attribute type="xs:string" name="tableref"/> | ||
| <xs:assert test="if (@tableref) then (@tableref != '') else true() "/> | ||
| <xs:assert test="every $child in ./dm-mapping:INSTANCE satisfies (not($child/@dmrole) or $child/@dmrole = '') "/> | ||
| </xs:complexType> | ||
| <!-- Mapping of either a Datatype or an Objecttype --> | ||
| <xs:complexType name="Instance"> | ||
| <xs:sequence> | ||
| <xs:choice maxOccurs="unbounded"> | ||
| <xs:element name="PRIMARY_KEY" type="dm-mapping:PrimaryKey" minOccurs="0"/> | ||
| </xs:choice> <!-- can this now be an xs:all --> | ||
| <xs:choice maxOccurs="unbounded"> | ||
| <xs:element name="REFERENCE" type="dm-mapping:Reference" minOccurs="0"/> | ||
| <xs:element name="ATTRIBUTE" type="dm-mapping:Attribute" minOccurs="0"/> | ||
| <xs:element name="INSTANCE" type="dm-mapping:Instance" minOccurs="0"/> | ||
| <xs:element name="COLLECTION" type="dm-mapping:Collection" minOccurs="0"/> | ||
| </xs:choice> | ||
| </xs:sequence> | ||
| <xs:attribute type="xs:string" name="dmrole" use="optional"/> | ||
| <xs:attribute type="xs:string" name="dmtype" use="required"/> | ||
| <xs:attribute type="xs:string" name="dmid"/> | ||
| <!-- xs:assert test="(not(./@dmid) and @dmrole != '') or @dmid != '' " | ||
| /> --> | ||
| <xs:assert test=" @dmtype != '' "/> | ||
| <xs:assert test="if (@dmid) then ( @dmid != '') else true() "/> | ||
| <xs:assert test="every $child in ./dm-mapping:INSTANCE satisfies $child/@dmrole != '' "/> | ||
| <xs:assert test="every $child in ./dm-mapping:COLLECTION satisfies $child/@dmrole != '' "/> | ||
| <xs:assert test="every $child in ./dm-mapping:COLLECTION satisfies not($child/@dmid) or $child/@dmid = '' "/> | ||
| <xs:assert test="every $child in ./dm-mapping:ATTRIBUTE satisfies $child/@dmrole != '' "/> | ||
| <xs:assert test="every $child in ./dm-mapping:REFERENCE satisfies $child/@dmrole != '' "/> | ||
| </xs:complexType> | ||
| <!-- Atomic attribute --> | ||
| <xs:complexType name="Attribute"> | ||
| <xs:attribute type="xs:string" name="dmrole" use="optional"/> | ||
| <xs:attribute type="xs:string" name="dmtype" use="required"/> | ||
| <xs:attribute type="xs:string" name="ref"/> | ||
| <xs:attribute type="xs:string" name="value"/> | ||
| <xs:attribute type="xs:string" name="unit"/> | ||
| <xs:attribute type="xs:string" name="arrayindex"/> | ||
| <xs:assert test="if (./@arrayindex) then (./@ref) else true()"/> | ||
| <xs:assert test="(not(./@ref) and ./@value) or (not(./@value) and ./@ref) or (./@value and ./@ref)"/> | ||
| <xs:assert test="if (@ref) then (@ref != '') else true() "/> | ||
| <xs:assert test="if (@arrayindex) then (@arrayindex >= '0') else true() "/> | ||
| <xs:assert test="@dmtype != '' "/> | ||
| </xs:complexType> | ||
| <!-- Data list mapping block --> | ||
| <xs:complexType name="Collection"> | ||
| <xs:choice maxOccurs="unbounded"> | ||
| <xs:element name="REFERENCE" type="dm-mapping:Reference" minOccurs="0"/> | ||
| <xs:element name="INSTANCE" type="dm-mapping:Instance" minOccurs="0"/> | ||
| <xs:element name="ATTRIBUTE" type="dm-mapping:Attribute" minOccurs="0"/> | ||
| <xs:element name="COLLECTION" type="dm-mapping:Collection" minOccurs="0"/> | ||
| <xs:element name="JOIN" type="dm-mapping:Join" minOccurs="0" maxOccurs="1"/> | ||
| </xs:choice> | ||
| <xs:attribute type="xs:string" name="dmrole" use="optional"/> | ||
| <xs:attribute type="xs:string" name="size"/> | ||
| <xs:attribute type="xs:string" name="dmid"/> | ||
| <xs:assert test="if (@dmid) then ( @dmid != '') else true() "/> | ||
| <xs:assert test="if (count(dm-mapping:JOIN) > 0 ) then (count(dm-mapping:REFERENCE) = 0) else true()"/> | ||
| <xs:assert test="if (count(dm-mapping:JOIN) > 0 ) then (count(dm-mapping:INSTANCE) = 0) else true()"/> | ||
| <xs:assert test="if (count(dm-mapping:JOIN) > 0 ) then (count(dm-mapping:ATTRIBUTE) = 0) else true()"/> | ||
| <xs:assert test="if (count(dm-mapping:JOIN) > 0 ) then (count(dm-mapping:COLLECTION) = 0) else true()"/> | ||
| <xs:assert test="count(dm-mapping:ATTRIBUTE) eq 0 or (count(dm-mapping:ATTRIBUTE) gt 0 and count(dm-mapping:REFERENCE) eq 0 and count(dm-mapping:INSTANCE) eq 0 and count(dm-mapping:JOIN) eq 0 and count(dm-mapping:COLLECTION) eq 0)"/> | ||
| <xs:assert test="count(dm-mapping:REFERENCE) eq 0 or (count(dm-mapping:REFERENCE) gt 0 and count(dm-mapping:ATTRIBUTE) eq 0 and count(dm-mapping:INSTANCE) eq 0 and count(dm-mapping:JOIN) eq 0 and count(dm-mapping:COLLECTION) eq 0)"/> | ||
| <xs:assert test="count(dm-mapping:INSTANCE) eq 0 or (count(dm-mapping:INSTANCE) gt 0 and count(dm-mapping:ATTRIBUTE) eq 0 and count(dm-mapping:REFERENCE) eq 0 and count(dm-mapping:COLLECTION) eq 0)"/> | ||
| <xs:assert test="count(dm-mapping:JOIN) eq 0 or (count(dm-mapping:JOIN) gt 0 and count(dm-mapping:ATTRIBUTE) eq 0 and count(dm-mapping:REFERENCE) eq 0 and count(dm-mapping:COLLECTION) eq 0)"/> | ||
| <xs:assert test="count(dm-mapping:COLLECTION) eq 0 or (count(dm-mapping:COLLECTION) gt 0 and count(dm-mapping:ATTRIBUTE) eq 0 and count(dm-mapping:REFERENCE) eq 0 and count(dm-mapping:INSTANCE) eq 0 and count(dm-mapping:JOIN) eq 0)"/> | ||
| <xs:assert test="count (dm-mapping:INSTANCE[@dmrole != '']) eq 0"/> | ||
| <xs:assert test="count (dm-mapping:ATTRIBUTE[@dmrole != '']) eq 0"/> | ||
| <xs:assert test="count (dm-mapping:COLLECTION[@dmrole != '']) eq 0"/> | ||
| <xs:assert test="count (dm-mapping:REFERENCE[@dmrole != '']) eq 0"/> | ||
| </xs:complexType> | ||
| <xs:complexType name="Reference"> | ||
| <xs:sequence> | ||
| <xs:element name="FOREIGN_KEY" type="dm-mapping:ForeignKey" minOccurs="0" maxOccurs="unbounded"/> | ||
| </xs:sequence> | ||
| <xs:attribute type="xs:string" name="dmrole" use="optional"/> | ||
| <xs:attribute type="xs:string" name="sourceref"/> | ||
| <xs:attribute type="xs:string" name="dmref"/> | ||
| <xs:assert test="if (./@sourceref) then @sourceref != '' else true()"/> | ||
| <xs:assert test="if (./@dmref) then @dmref != '' else true()"/> | ||
| <xs:assert test="(./@dmref and not(./@sourceref)) or (not(./@dmref) and ./@sourceref)"/> | ||
| <xs:assert test="((count(dm-mapping:FOREIGN_KEY) > 0 and ./@sourceref and not(./@dmref)) or (count(./dm-mapping:FOREIGN_KEY) eq 0 and not(./@sourceref) and ./@dmref))"/> | ||
| </xs:complexType> | ||
| <!-- Join with another table. --> | ||
| <xs:complexType name="Join"> | ||
| <xs:sequence> | ||
| <xs:element name="WHERE" type="dm-mapping:Where" minOccurs="0" maxOccurs="unbounded"/> | ||
| </xs:sequence> | ||
| <xs:attribute type="xs:string" name="sourceref"/> | ||
| <xs:attribute type="xs:string" name="dmref"/> | ||
| <xs:assert test="if (./@sourceref) then @sourceref != '' else true()"/> | ||
| <xs:assert test="if (./@dmref) then @dmref != '' else true()"/> | ||
| <xs:assert test="((./@sourceref) and (./@dmref)) or not(./@sourceref) or (count(dm-mapping:WHERE) > 0 and (./@sourceref))"/> | ||
| </xs:complexType> | ||
| <!-- Select table rows with value of the column @ref = @value --> | ||
| <xs:complexType name="Where"> | ||
| <xs:attribute type="xs:string" name="foreignkey"/> | ||
| <xs:attribute type="xs:string" name="primarykey"/> | ||
| <xs:attribute type="xs:string" name="value"/> | ||
| <xs:assert test="(./@foreignkey and ./@primarykey and not(@value)) or (./@foreignkey and not(./@primarykey) and @value) or (not(./@foreignkey) and ./@primarykey and @value)"/> | ||
| <xs:assert test="if (./@foreignkey) then @foreignkey != '' else true()"/> | ||
| <xs:assert test="if (./@primarykey) then @primarykey != '' else true()"/> | ||
| </xs:complexType> | ||
| <xs:complexType name="PrimaryKey"> | ||
| <xs:attribute type="xs:string" name="ref"/> | ||
| <xs:attribute type="xs:string" name="dmtype"/> | ||
| <xs:attribute type="xs:string" name="value"/> | ||
| <xs:assert test="./@ref or ./@value "/> | ||
| <xs:assert test="@dmtype != '' "/> | ||
| <xs:assert test="if (./@ref) then @ref != '' else true()"/> | ||
| <xs:assert test="(./@value and not(./@ref)) or (not(./@value) and ./@ref)"/> | ||
| </xs:complexType> | ||
| <xs:complexType name="ForeignKey"> | ||
| <xs:attribute type="xs:string" name="ref" use="required"/> | ||
| <xs:assert test="@ref != ''"/> | ||
| </xs:complexType> | ||
| </xs:schema> |
@@ -26,3 +26,3 @@ # This test job is separated out into its own workflow to be able to trigger separately | ||
| - name: Set up Python 3.12 | ||
| uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | ||
| with: | ||
@@ -36,3 +36,3 @@ python-version: "3.12" | ||
| - name: Upload coverage to codecov | ||
| uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v5.4.0 | ||
| uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 | ||
| with: | ||
@@ -47,3 +47,3 @@ file: ./coverage.xml | ||
| - name: Set up Python 3.13 | ||
| uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | ||
| with: | ||
@@ -50,0 +50,0 @@ python-version: "3.13-dev" |
@@ -27,8 +27,8 @@ # Developer version testing is in separate workflow | ||
| include: | ||
| - name: py38 oldest dependencies, Linux | ||
| python-version: '3.8' | ||
| tox_env: py38-test-oldestdeps-alldeps | ||
| - name: py39 mandatory dependencies only, Linux | ||
| - name: py39 oldest dependencies, Linux | ||
| python-version: '3.9' | ||
| tox_env: py39-test | ||
| tox_env: py39-test-oldestdeps-alldeps | ||
| - name: py310 mandatory dependencies only, Linux | ||
| python-version: '3.10' | ||
| tox_env: py310-test | ||
| - name: py311 with online tests, Linux | ||
@@ -44,3 +44,3 @@ python-version: '3.11' | ||
| - name: Set up Python | ||
| uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | ||
| with: | ||
@@ -66,9 +66,9 @@ python-version: ${{ matrix.python-version }} | ||
| - name: Set up Python | ||
| uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | ||
| with: | ||
| python-version: '3.10' | ||
| python-version: '3.12' | ||
| - name: Install tox | ||
| run: python -m pip install --upgrade tox | ||
| - name: Python 3.10 with latest astropy | ||
| run: tox -e py310-test-alldeps | ||
| - name: Python 3.12 with latest astropy | ||
| run: tox -e py312-test-alldeps | ||
@@ -82,6 +82,6 @@ | ||
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | ||
| - name: Set up Python 3.8 | ||
| uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 | ||
| - name: Set up Python 3.12 | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | ||
| with: | ||
| python-version: 3.8 | ||
| python-version: '3.12' | ||
| - name: Install tox | ||
@@ -100,3 +100,3 @@ run: python -m pip install --upgrade tox | ||
| - name: Set up Python 3.10 | ||
| uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0 | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | ||
| with: | ||
@@ -103,0 +103,0 @@ python-version: '3.10' |
+1
-0
@@ -20,2 +20,3 @@ # Compiled files | ||
| .hypothesis | ||
| *api_sample* | ||
@@ -22,0 +23,0 @@ # Sphinx |
+4
-0
@@ -11,3 +11,7 @@ Adam Ginsburg <keflavich@gmail.com> | ||
| Hugo van Kemenade <hugovk@users.noreply.github.com> | ||
| Hugo van Kemenade <hugovk@users.noreply.github.com> <1324225+hugovk@users.noreply.github.com> | ||
| Manon Marchand <manonmarchand22@gmail.com> | ||
| Markus Demleitner <m@tfiu.de> | ||
| Markus Demleitner <m@tfiu.de> <msdemlei@ari.uni-heidelberg.de> | ||
| Laurent Michel <laurent.michel@astro.unistra.fr> | ||
| Pey Lian Lim <2090236+pllim@users.noreply.github.com> | ||
@@ -14,0 +18,0 @@ Ray Plante <rplante@ncsa.uiuc.edu> <rplante@ncsa.illinois.edu> |
+32
-6
@@ -0,1 +1,33 @@ | ||
| 1.7 (2025-06-01) | ||
| ================ | ||
| Enhancements and Fixes | ||
| ---------------------- | ||
| - Extend the MIVOT module with the ability to build annotations component by | ||
| component and put them into a VOTable. [#627] | ||
| - Add an API helping to map VOtable data in the Mango data model by using | ||
| MIVOT [#664] | ||
| - Make deletion of TAP jobs optional via a new ``delete`` kwarg. [#640] | ||
| - Correctly delete jobs in ``TAPService.run_async`` even when the server | ||
| returns an error. [#667] | ||
| - Change AsyncTAPJob.result to return None if no result is found explicitly. | ||
| [#644] | ||
| - Add a UAT constraint to the registry interface for constraining | ||
| subjects [#649] | ||
| - Fixed AttributeError when a capability has None standardID in SIA2Service. | ||
| [#669] | ||
| Deprecations and Removals | ||
| ------------------------- | ||
| - Versions of Python <3.9 are no longer supported. [#639] | ||
| 1.6.2 (2025-04-07) | ||
@@ -70,8 +102,2 @@ ================== | ||
| Bug Fixes | ||
| --------- | ||
| - Fix propagating some previously swallowed exceptions. [#614] | ||
| Deprecations and Removals | ||
@@ -78,0 +104,0 @@ ------------------------- |
@@ -18,3 +18,3 @@ .. _pyvo-data-access: | ||
| >>> import pyvo as vo | ||
| >>> service = vo.dal.SIAService("http://dc.zah.uni-heidelberg.de/lswscans/res/positions/siap/siap.xml") | ||
| >>> service = vo.dal.SIAService("http://dc.g-vo.org/lswscans/res/positions/siap/siap.xml") | ||
| >>> print(service.description) | ||
@@ -477,3 +477,3 @@ Scans of plates kept at Landessternwarte Heidelberg-Königstuhl. They | ||
| >>> size = Quantity(0.5, unit="deg") | ||
| >>> sia_service = vo.dal.SIAService("http://dc.zah.uni-heidelberg.de/hppunion/q/im/siap.xml") | ||
| >>> sia_service = vo.dal.SIAService("http://dc.g-vo.org/hppunion/q/im/siap.xml") | ||
| >>> sia_results = sia_service.search(pos=pos, size=size) | ||
@@ -570,3 +570,3 @@ | ||
| >>> scs_srv = vo.dal.SCSService('http://dc.zah.uni-heidelberg.de/arihip/q/cone/scs.xml') | ||
| >>> scs_srv = vo.dal.SCSService('http://dc.g-vo.org/arihip/q/cone/scs.xml') | ||
| >>> scs_results = scs_srv.search(pos=pos, radius=size) | ||
@@ -760,3 +760,3 @@ | ||
| >>> row.getdataurl() | ||
| 'http://dc.zah.uni-heidelberg.de/getproduct/califa/datadr3/V500/NGC0551.V500.rscube.fits' | ||
| 'http://dc.g-vo.org/getproduct/califa/datadr3/V500/NGC0551.V500.rscube.fits' | ||
| >>> type(row.getdataset()) | ||
@@ -763,0 +763,0 @@ <class 'urllib3.response.HTTPResponse'> |
@@ -171,5 +171,7 @@ .. _pyvo-discover: | ||
| discoverer.set_services( | ||
| registry.search(registry.Author("Hubble, %"))) | ||
| registry.search(registry.UAT("galaxies", expand_down=3))) | ||
| to query services that give a particular author. More realistically, | ||
| to query services that claim to deal with galaxies or perhaps more | ||
| specific concepts (although this *will* pull a lot of extra services | ||
| that the discoverer will just discard). More realistically, | ||
@@ -176,0 +178,0 @@ :: |
+21
-192
@@ -1,6 +0,6 @@ | ||
| ******************** | ||
| MIVOT (`pyvo.mivot`) | ||
| ******************** | ||
| ********************** | ||
| MIVOT (``pyvo.mivot``) | ||
| ********************** | ||
| This module contains the new feature of annotations in VOTable. | ||
| This module contains the new feature of handling model annotations in VOTable. | ||
| Astropy version >= 6.0 is required. | ||
@@ -31,3 +31,3 @@ | ||
| Implementation Scope | ||
| -------------------- | ||
| ==================== | ||
| This implementation is totally model-agnostic. | ||
@@ -43,7 +43,7 @@ | ||
| Some of the examples have been provided by a special end-point of the Vizier cone-search service | ||
| (https://cdsarc.cds.unistra.fr/beta/viz-bin/mivotconesearch) that maps query results to this model. | ||
| (https://vizier.cds.unistra.fr/viz-bin/conesearch/V1.5/) that maps query results to this model. | ||
| .. image:: _images/mangoEpochPosition.png | ||
| :width: 500 | ||
| :alt: EpochPropagation class used to validate this api. | ||
| :width: 500 | ||
| :alt: EpochPropagation class used to validate this api. | ||
@@ -61,189 +61,18 @@ It is to be noted that the Vizier service does not annotate errors at the time of writing (Q1 2024) | ||
| - ``JOIN`` features are not supported. | ||
| - ``TEMPLATES`` with more than one ``INSANCE`` not supported. | ||
| - ``TEMPLATES`` with more than one ``INSTANCE`` not supported. | ||
| Integrated Readout | ||
| ------------------ | ||
| The ``ModelViewer`` module manages access to data mapped to a model through dynamically | ||
| generated objects (``MivotInstance``class). | ||
| The example below shows how a VOTable, resulting from a cone-search query which data are mapped | ||
| to the ``EpochPosition`` class, can be consumed. | ||
| .. doctest-remote-data:: | ||
| >>> import astropy.units as u | ||
| >>> from astropy.coordinates import SkyCoord | ||
| >>> from pyvo.dal.scs import SCSService | ||
| >>> from pyvo.utils.prototype import activate_features | ||
| >>> from pyvo.mivot.version_checker import check_astropy_version | ||
| >>> from pyvo.mivot.viewer.mivot_viewer import MivotViewer | ||
| >>> activate_features("MIVOT") | ||
| >>> if check_astropy_version() is False: | ||
| ... pytest.skip("MIVOT test skipped because of the astropy version.") | ||
| >>> scs_srv = SCSService("https://cdsarc.cds.unistra.fr/beta/viz-bin/mivotconesearch/I/239/hip_main") | ||
| >>> m_viewer = MivotViewer( | ||
| ... scs_srv.search( | ||
| ... pos=SkyCoord(ra=52.26708 * u.degree, dec=59.94027 * u.degree, frame='icrs'), | ||
| ... radius=0.05 | ||
| ... ) | ||
| ... ) | ||
| >>> mivot_instance = m_viewer.dm_instance | ||
| >>> print(mivot_instance.dmtype) | ||
| mango:EpochPosition | ||
| >>> print(mivot_instance.coordSys.spaceRefFrame.value) | ||
| ICRS | ||
| >>> while m_viewer.next(): | ||
| ... print(f"position: {mivot_instance.latitude.value} {mivot_instance.longitude.value}") | ||
| position: 59.94033461 52.26722684 | ||
| Using the MIVOT package | ||
| ======================= | ||
| The ``pyvo.mivot`` module can be used to either read or build annotations. | ||
| In this example, the data readout is totally managed by the ``MivotViewer`` instance. | ||
| The ``astropy.io.votable`` API is encapsulated in this module. | ||
| Model leaves (class attributes) are complex types that provide additional information: | ||
| - ``value``: attribute value | ||
| - ``dmtype``: attribute type such as defined in the Mivot annotations | ||
| - ``unit``: attribute unit such as defined in the Mivot annotations | ||
| - ``ref``: identifier of the table column mapped on the attribute | ||
| The model view on a data row can also be passed as a Python dictionary | ||
| using the ``to_dict()`` method of ``MivotInstance``. | ||
| .. code-block:: python | ||
| :caption: Working with a model view as a dictionary | ||
| (the JSON layout has been squashed for display purpose) | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| m_viewer = MivotViewer(path_to_votable) | ||
| mivot_instance = m_viewer.dm_instance | ||
| mivot_object_dict = mivot_object.to_dict() | ||
| DictUtils.print_pretty_json(mivot_object_dict) | ||
| { | ||
| "dmtype": "mango:EpochPosition", | ||
| "longitude": {"value": 359.94372764, "unit": "deg"}, | ||
| "latitude": {"value": -0.28005255, "unit": "deg"}, | ||
| "pmLongitude": {"value": -5.14, "unit": "mas/yr"}, | ||
| "pmLatitude": {"value": -25.43, "unit": "mas/yr"}, | ||
| "epoch": {"value": 1991.25, "unit": "year"}, | ||
| "coordSys": { | ||
| "dmtype": "coords:SpaceSys", | ||
| "dmid": "ICRS", | ||
| "dmrole": "coords:Coordinate.coordSys", | ||
| "spaceRefFrame": {"value": "ICRS"}, | ||
| }, | ||
| } | ||
| - It is recommended to use a copy of the | ||
| dictionary as it will be rebuilt each time the ``to_dict()`` method is invoked. | ||
| - The default representation of ``MivotInstance`` instances is made with a pretty | ||
| string serialization of this dictionary (method ``__repr__()``). | ||
| - An extended version of the object dictionary e.g. with information about where | ||
| the values were picked from from, is available using the method ``to_hk_dict()``. | ||
| Per-Row Readout | ||
| --------------- | ||
| The annotation schema can also be applied to table rows read outside of the ``MivotViewer`` | ||
| with the `astropy.io.votable` API: | ||
| .. code-block:: python | ||
| :caption: Accessing the model view of Astropy table rows | ||
| votable = parse(path_to_votable) | ||
| table = votable.resources[0].tables[0] | ||
| # init the viewer | ||
| mivot_viewer = MivotViewer(votable, resource_number=0) | ||
| mivot_object = mivot_viewer.dm_instance | ||
| # and feed it with the table row | ||
| read = [] | ||
| for rec in table.array: | ||
| mivot_object.update(rec) | ||
| read.append(mivot_object.longitude.value) | ||
| # show that the model retrieve the correct data values | ||
| assert rec["RAICRS"] == mivot_object.longitude.value | ||
| assert rec["DEICRS"] == mivot_object.latitude.value | ||
| In this case, it is up to the user to ensure that the read data rows are those mapped by the Mivot annotations. | ||
| Get a SkyCoord Instance Directly From the Annotations | ||
| ----------------------------------------------------- | ||
| Once you get a ``MivotInstance`` representing the last row read, you can use it to create an ``astropy.SkyCoord`` object. | ||
| .. code-block:: python | ||
| :caption: Accessing the model view of Astropy table rows | ||
| from pyvo.mivot import MivotViewer | ||
| m_viewer = MivotViewer(path_to_votable) | ||
| mivot_instance = m_viewer.dm_instance | ||
| print(mivot_instance.get_SkyCoord()) | ||
| <SkyCoord (ICRS): (ra, dec) in deg(52.26722684, 59.94033461) | ||
| (pm_ra_cosdec, pm_dec) in mas / yr(-0.82, -1.85)> | ||
| This feature works under the condition that the annotations contain a valid instance of ``mango:EPochPosition``, otherwise | ||
| a ``NoMatchingDMTypeError`` is thrown. | ||
| Although not a standard at the time of writing, the class structure supported by this implementation must match the figure above. | ||
| For XML Hackers | ||
| --------------- | ||
| The model instances can also be serialized as XML elements that can be parsed with XPath queries. | ||
| .. code-block:: python | ||
| :caption: Accessing the XML view of the mapped model instances | ||
| with MivotViewer(path_to_votable) as mivot_viewer: | ||
| while mivot_viewer.next(): | ||
| xml_view = mivot_viewer.xml_view | ||
| # do whatever you want with this XML element | ||
| It to be noted that ``mivot_viewer.xml_view`` is a shortcut | ||
| for ``mivot_viewer.xml_view.view`` where ``mivot_viewer.xml_view`` | ||
| is is an instance of ``pyvo.mivot.viewer.XmlViewer``. | ||
| This object provides many functions facilitating the XML parsing. | ||
| Class Generation in a Nutshell | ||
| ------------------------------ | ||
| MIVOT reconstructs model structures with 3 elements: | ||
| - ``INSTANCE`` for the objects | ||
| - ``ATTRIBUTE`` for the attributes | ||
| - ``COLLECTION`` for the elements with a cardinality greater than 1 | ||
| The role played by each of these elements in the model hierarchy is defined | ||
| by its ``@dmrole`` XML attribute. Types of both ``INSTANCE`` and ``ATTRIBUTE`` are defined by | ||
| their ``@dmtype`` XML attributes. | ||
| ``MivotInstance`` classes are built by following MIVOT annotation structure: | ||
| - ``INSTANCE`` are represented by Python classes | ||
| - ``ATTRIBUTE`` are represented by Python class fields | ||
| - ``COLLECTION`` are represented by Python lists ([]) | ||
| ``@dmrole`` and ``@dmtype`` cannot be used as Python keywords as such, because they are built from VO-DML | ||
| identifiers, which have the following structure: ``model:a.b``. | ||
| - Only the last part of the path is kept for attribute names. | ||
| - For class names, forbidden characters (``:`` or ``.``) are replaced with ``_``. | ||
| - Original ``@dmtype`` are kept as attributes of generated Python objects. | ||
| - The structure of the ``MivotInstance`` objects can be inferred from the mapped model in 2 different ways: | ||
| - 1. From the MIVOT instance property ``MivotInstance.to_dict()`` a shown above. | ||
| This is a pure Python dictionary but its access can be slow because it is generated | ||
| on the fly each time the property is invoked. | ||
| - 2. From the internal class dictionary ``MivotInstance.__dict__`` | ||
| (see the Python `data model <https://docs.python.org/3/reference/datamodel.html>`_). | ||
| Reference/API | ||
| ============= | ||
| .. automodapi:: pyvo.mivot | ||
| .. automodapi:: pyvo.mivot.viewer | ||
| .. automodapi:: pyvo.mivot.seekers | ||
| .. automodapi:: pyvo.mivot.features | ||
| .. automodapi:: pyvo.mivot.utils | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
| viewer | ||
| annoter | ||
| writer | ||
| example | ||
| annoter_tips | ||
@@ -57,2 +57,4 @@ .. _pyvo-registry: | ||
| UCD (e.g., ``phot.mag;em.ir.%`` for “any infrared magnitude”). | ||
| * :py:class:`~pyvo.registry.UAT` (``uat``): constrain by concepts | ||
| from the IVOA Unified Astronomy Thesaurus http://www.ivoa.net/rdf/uat. | ||
| * :py:class:`~pyvo.registry.Waveband` (``waveband``): one or more terms | ||
@@ -101,8 +103,21 @@ from the vocabulary at http://www.ivoa.net/rdf/messenger giving the rough | ||
| or a mixture between the two. Constructing using explicit | ||
| constraints is generally preferable with more complex queries. Where | ||
| the constraints accept multiple arguments, you can pass in sequences to | ||
| the keyword arguments; for instance: | ||
| constraints is generally preferable with more complex queries. | ||
| An advantage of using explicit constraints is that you can pass | ||
| additional parameters to the constraints. For instance, the UAT | ||
| constraint can optionally expand your keyword to narrower or wider | ||
| concepts. When looking for resources talking about Cepheids of all | ||
| kinds, you can thus say: | ||
| .. doctest-remote-data:: | ||
| >>> resources = registry.search( | ||
| ... registry.UAT("cepheid-variable-stars", expand_down=3)) | ||
| There is no way to express this using keyword arguments. | ||
| However, where the constraints accept multiple equivalent arguments, you | ||
| can pass in sequences to the keyword arguments; for instance: | ||
| .. doctest-remote-data:: | ||
| >>> resources = registry.search(registry.Waveband("Radio", "Millimeter"), | ||
@@ -118,2 +133,3 @@ ... registry.Author("%Miller%")) | ||
| There is also :py:meth:`~pyvo.registry.get_RegTAP_query`, accepting the | ||
@@ -244,4 +260,4 @@ same arguments as :py:meth:`pyvo.registry.search`. This function simply | ||
| ... print(interface) | ||
| Interface(type='tap#aux', description='', url='http://tapvizier.cds.unistra.fr/TAPVizieR/tap') | ||
| Interface(type='vr:webbrowser', description='', url='http://vizier.cds.unistra.fr/viz-bin/VizieR-2?-source=J/ApJ/727/14') | ||
| Interface(type='tap#aux', description='', url='https://tapvizier.cds.unistra.fr/TAPVizieR/tap') | ||
| Interface(type='vr:webbrowser', description='', url='https://vizier.cds.unistra.fr/viz-bin/VizieR-2?-source=J/ApJ/727/14') | ||
| Interface(type='conesearch', description='Cone search capability for table J/ApJ/727/14/table2 (AKARI IRC 3-24{mu}m, and Spitzer MIPS 24/70{mu}m photometry of Abell 2255 member galaxies)', url='https://vizier.cds.unistra.fr/viz-bin/conesearch/J/ApJ/727/14/table2?') | ||
@@ -254,3 +270,3 @@ | ||
| >>> voresource.list_interfaces()[0].to_service() | ||
| TAPService(baseurl : 'http://tapvizier.cds.unistra.fr/TAPVizieR/tap', description : '') | ||
| TAPService(baseurl : 'https://tapvizier.cds.unistra.fr/TAPVizieR/tap', description : '') | ||
@@ -263,3 +279,3 @@ The list of interfaces can also be filtered to interfaces corresponding to services of a | ||
| >>> voresource.list_interfaces("tap") | ||
| [Interface(type='tap#aux', description='', url='http://tapvizier.cds.unistra.fr/TAPVizieR/tap')] | ||
| [Interface(type='tap#aux', description='', url='https://tapvizier.cds.unistra.fr/TAPVizieR/tap')] | ||
@@ -305,5 +321,4 @@ To operate TAP services, you need to know what tables make up a | ||
| also want to have a look at Aladin's discovery tree, TOPCAT's VO menu, | ||
| or at services like DataScope_ or WIRR_ in your web browser. | ||
| or at services like WIRR_ in your web browser. | ||
| .. _DataScope: https://heasarc.gsfc.nasa.gov/cgi-bin/vo/datascope/init.pl | ||
| .. _WIRR: https://dc.g-vo.org/WIRR | ||
@@ -310,0 +325,0 @@ |
+7
-7
| Metadata-Version: 2.4 | ||
| Name: pyvo | ||
| Version: 1.6.2 | ||
| Version: 1.7 | ||
| Summary: Astropy affiliated package for accessing Virtual Observatory data and services | ||
@@ -16,5 +16,5 @@ Author: the PyVO Developers | ||
| Classifier: Topic :: Software Development :: Libraries | ||
| Requires-Python: >=3.8 | ||
| Requires-Python: >=3.9 | ||
| License-File: LICENSE.rst | ||
| Requires-Dist: astropy>=4.1 | ||
| Requires-Dist: astropy>=4.2 | ||
| Requires-Dist: requests | ||
@@ -65,3 +65,3 @@ Provides-Extra: all | ||
| Source code can be found `on GitHub <http://github.com/astropy/pyvo>`_ | ||
| Source code can be found `on GitHub <https://github.com/astropy/pyvo>`_ | ||
@@ -71,3 +71,3 @@ Installation and Requirements | ||
| Releases of PyVO are available from `PyPI <https://pypi.python.org/pypi/pyvo>`_ | ||
| Releases of PyVO are available from `PyPI <https://pypi.org/project/pyvo/>`_ | ||
| thus, it and its prerequisites can be most easily installed using ``pip``: | ||
@@ -87,3 +87,3 @@ | ||
| * `astropy <https://astropy.org>`__ (>=4.1) | ||
| * `requests <http://docs.python-requests.org/en/latest/>`_ | ||
| * `requests <https://docs.python-requests.org/en/latest/>`_ | ||
@@ -124,3 +124,3 @@ The following packages are optional dependencies and are required for the | ||
| Many instructive examples can be found in the `PyVO Documentation <http://pyvo.readthedocs.org>`_. | ||
| Many instructive examples can be found in the `PyVO Documentation <https://pyvo.readthedocs.io/en/latest/>`_. | ||
| Additional examples can be found in the examples directory. | ||
@@ -127,0 +127,0 @@ |
| Metadata-Version: 2.4 | ||
| Name: pyvo | ||
| Version: 1.6.2 | ||
| Version: 1.7 | ||
| Summary: Astropy affiliated package for accessing Virtual Observatory data and services | ||
@@ -16,5 +16,5 @@ Author: the PyVO Developers | ||
| Classifier: Topic :: Software Development :: Libraries | ||
| Requires-Python: >=3.8 | ||
| Requires-Python: >=3.9 | ||
| License-File: LICENSE.rst | ||
| Requires-Dist: astropy>=4.1 | ||
| Requires-Dist: astropy>=4.2 | ||
| Requires-Dist: requests | ||
@@ -65,3 +65,3 @@ Provides-Extra: all | ||
| Source code can be found `on GitHub <http://github.com/astropy/pyvo>`_ | ||
| Source code can be found `on GitHub <https://github.com/astropy/pyvo>`_ | ||
@@ -71,3 +71,3 @@ Installation and Requirements | ||
| Releases of PyVO are available from `PyPI <https://pypi.python.org/pypi/pyvo>`_ | ||
| Releases of PyVO are available from `PyPI <https://pypi.org/project/pyvo/>`_ | ||
| thus, it and its prerequisites can be most easily installed using ``pip``: | ||
@@ -87,3 +87,3 @@ | ||
| * `astropy <https://astropy.org>`__ (>=4.1) | ||
| * `requests <http://docs.python-requests.org/en/latest/>`_ | ||
| * `requests <https://docs.python-requests.org/en/latest/>`_ | ||
@@ -124,3 +124,3 @@ The following packages are optional dependencies and are required for the | ||
| Many instructive examples can be found in the `PyVO Documentation <http://pyvo.readthedocs.org>`_. | ||
| Many instructive examples can be found in the `PyVO Documentation <https://pyvo.readthedocs.io/en/latest/>`_. | ||
| Additional examples can be found in the examples directory. | ||
@@ -127,0 +127,0 @@ |
@@ -1,2 +0,2 @@ | ||
| astropy>=4.1 | ||
| astropy>=4.2 | ||
| requests | ||
@@ -3,0 +3,0 @@ |
@@ -16,2 +16,3 @@ .gitignore | ||
| .github/dependabot.yml | ||
| .github/release.yml | ||
| .github/workflows/changelog.yml | ||
@@ -35,4 +36,14 @@ .github/workflows/ci_devtests.yml | ||
| docs/io/vosi.rst | ||
| docs/mivot/annoter.rst | ||
| docs/mivot/annoter_tips.rst | ||
| docs/mivot/example.rst | ||
| docs/mivot/index.rst | ||
| docs/mivot/viewer.rst | ||
| docs/mivot/writer.rst | ||
| docs/mivot/_images/filterProfileService.png | ||
| docs/mivot/_images/mangoDataOrigin.png | ||
| docs/mivot/_images/mangoEpochPosition.png | ||
| docs/mivot/_images/mangoProperties.png | ||
| docs/mivot/_images/xtapdbSED.png | ||
| docs/mivot/_images/xtapdbXML.png | ||
| docs/registry/index.rst | ||
@@ -196,2 +207,3 @@ docs/utils/index.rst | ||
| pyvo/mivot/__init__.py | ||
| pyvo/mivot/glossary.py | ||
| pyvo/mivot/version_checker.py | ||
@@ -206,6 +218,10 @@ pyvo/mivot/features/__init__.py | ||
| pyvo/mivot/tests/__init__.py | ||
| pyvo/mivot/tests/conftest.py | ||
| pyvo/mivot/tests/test_annotation_seeker.py | ||
| pyvo/mivot/tests/test_header_mapper.py | ||
| pyvo/mivot/tests/test_mango_annoter.py | ||
| pyvo/mivot/tests/test_mivot_instance.py | ||
| pyvo/mivot/tests/test_mivot_instance_generation.py | ||
| pyvo/mivot/tests/test_mivot_viewer.py | ||
| pyvo/mivot/tests/test_mivot_writer.py | ||
| pyvo/mivot/tests/test_resource_seeker.py | ||
@@ -217,6 +233,14 @@ pyvo/mivot/tests/test_sky_coord_builder.py | ||
| pyvo/mivot/tests/test_xml_viewer.py | ||
| pyvo/mivot/tests/data/filter_gaia_grp.xml | ||
| pyvo/mivot/tests/data/filter_gaia_grvs.xml | ||
| pyvo/mivot/tests/data/static_reference.xml | ||
| pyvo/mivot/tests/data/test.header_extraction.1.xml | ||
| pyvo/mivot/tests/data/test.header_extraction.2.xml | ||
| pyvo/mivot/tests/data/test.header_extraction.xml | ||
| pyvo/mivot/tests/data/test.mango_annoter.xml | ||
| pyvo/mivot/tests/data/test.mivot_viewer.first_instance.xml | ||
| pyvo/mivot/tests/data/test.mivot_viewer.no_mivot.xml | ||
| pyvo/mivot/tests/data/test.mivot_viewer.xml | ||
| pyvo/mivot/tests/data/test.photcal_SDSS.xml | ||
| pyvo/mivot/tests/data/test.photcal_error.xml | ||
| pyvo/mivot/tests/data/reference/annotation_seeker.0.1.xml | ||
@@ -227,5 +251,11 @@ pyvo/mivot/tests/data/reference/annotation_seeker.0.2.xml | ||
| pyvo/mivot/tests/data/reference/instance_dmtypes.json | ||
| pyvo/mivot/tests/data/reference/mango_object.xml | ||
| pyvo/mivot/tests/data/reference/multiple_templates.xml | ||
| pyvo/mivot/tests/data/reference/static_reference_resolved.xml | ||
| pyvo/mivot/tests/data/reference/templates_models.json | ||
| pyvo/mivot/tests/data/reference/test_header_extraction.xml | ||
| pyvo/mivot/tests/data/reference/test_mivot_frames.xml | ||
| pyvo/mivot/tests/data/reference/test_mivot_photcal.xml | ||
| pyvo/mivot/tests/data/reference/test_mivot_writer.json | ||
| pyvo/mivot/tests/data/reference/test_mivot_writer.xml | ||
| pyvo/mivot/utils/__init__.py | ||
@@ -243,2 +273,9 @@ pyvo/mivot/utils/dict_utils.py | ||
| pyvo/mivot/viewer/xml_viewer.py | ||
| pyvo/mivot/writer/__init__.py | ||
| pyvo/mivot/writer/annotations.py | ||
| pyvo/mivot/writer/header_mapper.py | ||
| pyvo/mivot/writer/instance.py | ||
| pyvo/mivot/writer/instances_from_models.py | ||
| pyvo/mivot/writer/mango_object.py | ||
| pyvo/mivot/writer/mivot-v1.xsd | ||
| pyvo/registry/__init__.py | ||
@@ -245,0 +282,0 @@ pyvo/registry/regtap.py |
@@ -25,3 +25,3 @@ import logging | ||
| def __init__(self): | ||
| super(AuthSession, self).__init__() | ||
| super().__init__() | ||
| self.credentials = CredentialStore() | ||
@@ -28,0 +28,0 @@ self._auth_urls = AuthURLs() |
@@ -103,6 +103,5 @@ import collections | ||
| # auth method. | ||
| for url, method in sorted(self.base_urls.items(), | ||
| yield from sorted(self.base_urls.items(), | ||
| key=sort_by_len, | ||
| reverse=True): | ||
| yield url, method | ||
| reverse=True) | ||
@@ -109,0 +108,0 @@ def __repr__(self): |
@@ -10,3 +10,3 @@ import logging | ||
| class CredentialStore(object): | ||
| class CredentialStore: | ||
| """ | ||
@@ -13,0 +13,0 @@ The credential store takes user credentials, and uses them |
@@ -148,3 +148,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| raise DALServiceError( | ||
| "No Adhoc Service with ivo-id {}!".format(ivo_id)) | ||
| f"No Adhoc Service with ivo-id {ivo_id}!") | ||
@@ -169,3 +169,3 @@ def get_adhocservice_by_id(self, id_): | ||
| raise DALServiceError( | ||
| "No Adhoc Service with service_def id {}!".format(id_)) | ||
| f"No Adhoc Service with service_def id {id_}!") | ||
@@ -773,3 +773,3 @@ | ||
| semantics = set("#" + term for term in core_terms) | set(other_terms) | ||
| semantics = {"#" + term for term in core_terms} | set(other_terms) | ||
| for record in self: | ||
@@ -776,0 +776,0 @@ if record.semantics in semantics: |
@@ -53,3 +53,3 @@ """ | ||
| def __repr__(self): | ||
| return "{}: {}".format(self._typeName(self), self._reason) | ||
| return f"{self._typeName(self)}: {self._reason}" | ||
@@ -190,3 +190,3 @@ @property | ||
| if content_type and 'text/plain' in content_type: | ||
| message = '{} for {}'.format(response.text, url) | ||
| message = f'{response.text} for {url}' | ||
@@ -197,3 +197,3 @@ # TODO votable handling | ||
| elif isinstance(exc, Exception): | ||
| return DALServiceError("{}: {}".format(cls._typeName(exc), str(exc)), | ||
| return DALServiceError(f"{cls._typeName(exc)}: {str(exc)}", | ||
| cause=exc, url=url) | ||
@@ -200,0 +200,0 @@ else: |
@@ -91,3 +91,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| if not mtype or len(mtype) > 2: | ||
| raise ValueError("Can't parse mimetype \"{}\"".format(full_type)) | ||
| raise ValueError(f"Can't parse mimetype \"{full_type}\"") | ||
@@ -94,0 +94,0 @@ if mtype[0] == 'text': |
@@ -35,3 +35,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| raise KeyError('No param named {} defined'.format(keyword)) | ||
| raise KeyError(f'No param named {keyword} defined') | ||
@@ -336,3 +336,3 @@ | ||
| if radius <= 0 * u.deg or radius.to(u.deg) > 90 * u.deg: | ||
| raise ValueError('Invalid circle radius: {}'.format(radius)) | ||
| raise ValueError(f'Invalid circle radius: {radius}') | ||
| elif len(pos) == 3: | ||
@@ -346,3 +346,3 @@ self._validate_ra(pos[0]) | ||
| if radius <= 0 * u.deg or radius.to(u.deg) > 90 * u.deg: | ||
| raise ValueError('Invalid circle radius: {}'.format(radius)) | ||
| raise ValueError(f'Invalid circle radius: {radius}') | ||
| elif len(pos) == 4: | ||
@@ -375,3 +375,3 @@ ra_min = pos[0] if isinstance(pos[0], Quantity) else pos[0] * u.deg | ||
| if ra.to(u.deg).value < 0 or ra.to(u.deg).value > 360.0: | ||
| raise ValueError('Invalid ra: {}'.format(ra)) | ||
| raise ValueError(f'Invalid ra: {ra}') | ||
@@ -381,3 +381,3 @@ def _validate_dec(self, dec): | ||
| if dec.to(u.deg).value < -90.0 or dec.to(u.deg).value > 90.0: | ||
| raise ValueError('Invalid dec: {}'.format(dec)) | ||
| raise ValueError(f'Invalid dec: {dec}') | ||
@@ -432,3 +432,3 @@ | ||
| return '{} {}'.format(low, high) | ||
| return f'{low} {high}' | ||
@@ -462,3 +462,3 @@ | ||
| )) | ||
| return '{} {}'.format(min_time.mjd, max_time.mjd) | ||
| return f'{min_time.mjd} {max_time.mjd}' | ||
@@ -465,0 +465,0 @@ |
@@ -133,3 +133,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| print('DAL Service at {}'.format(self.baseurl)) | ||
| print(f'DAL Service at {self.baseurl}') | ||
@@ -556,3 +556,3 @@ | ||
| except KeyError: | ||
| raise KeyError("No such column: {}".format(name)) | ||
| raise KeyError(f"No such column: {name}") | ||
@@ -692,3 +692,3 @@ def getrecord(self, index): | ||
| except KeyError: | ||
| raise KeyError("No such column: {}".format(key)) | ||
| raise KeyError(f"No such column: {key}") | ||
@@ -896,3 +896,3 @@ def __iter__(self): | ||
| if not os.path.isdir(dir): | ||
| raise ValueError("{}: not a directory".format(dir)) | ||
| raise ValueError(f"{dir}: not a directory") | ||
@@ -912,3 +912,3 @@ if not base: | ||
| def mkpath(i): | ||
| return os.path.join(dir, "{}-{}.{}".format(base, i, ext)) | ||
| return os.path.join(dir, f"{base}-{i}.{ext}") | ||
@@ -923,3 +923,3 @@ if n > 0: | ||
| # never wrote a file of form, base-n.ext; try base.ext | ||
| path = os.path.join(dir, "{}.{}".format(base, ext)) | ||
| path = os.path.join(dir, f"{base}.{ext}") | ||
| if not os.path.exists(path): | ||
@@ -926,0 +926,0 @@ return path |
+5
-2
@@ -23,2 +23,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from .adhoc import DatalinkResultsMixin, AxisParamMixin, SodaRecordMixin, DatalinkRecordMixin | ||
| from .exceptions import DALServiceError | ||
| from .params import IntervalQueryParam, StrQueryParam, EnumQueryParam | ||
@@ -190,3 +191,3 @@ from .vosi import AvailabilityMixin, CapabilityMixin | ||
| # in pyvo. So pick any access url as long as it's not | ||
| if cap.standardid.lower() == SIA2_STANDARD_ID.lower(): | ||
| if cap.standardid and cap.standardid.lower() == SIA2_STANDARD_ID.lower(): | ||
| for interface in cap.interfaces: | ||
@@ -202,2 +203,4 @@ if interface.accessurls and \ | ||
| break | ||
| else: | ||
| raise DALServiceError("This URL does not seem to correspond to an SIA2 service.") | ||
@@ -345,3 +348,3 @@ def search(self, pos=None, *, band=None, time=None, pol=None, | ||
| if isinstance(kw, tuple): | ||
| val = '{} {}'.format(kw[0], kw[1]) | ||
| val = f'{kw[0]} {kw[1]}' | ||
| else: | ||
@@ -348,0 +351,0 @@ val = str(kw) |
+55
-26
@@ -154,3 +154,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| if self._tables is None: | ||
| tables_url = '{}/tables'.format(self.baseurl) | ||
| tables_url = f'{self.baseurl}/tables' | ||
@@ -209,3 +209,3 @@ response = self._session.get(tables_url, params={"detail": "min"}, stream=True) | ||
| if self._examples is None: | ||
| examples_url = '{}/examples'.format(self.baseurl) | ||
| examples_url = f'{self.baseurl}/examples' | ||
@@ -291,3 +291,3 @@ self._examples = self._parse_examples(examples_url) | ||
| self, query, *, language="ADQL", maxrec=None, uploads=None, | ||
| **keywords): | ||
| delete=True, **keywords): | ||
| """ | ||
@@ -307,2 +307,4 @@ runs async query and returns its result | ||
| a mapping from table names to objects containing a votable | ||
| delete : bool | ||
| delete the job after fetching the results | ||
@@ -332,6 +334,15 @@ Returns | ||
| job = job.run().wait() | ||
| job.raise_if_error() | ||
| try: | ||
| job.raise_if_error() | ||
| except DALQueryError: | ||
| if delete: | ||
| job.delete() | ||
| raise | ||
| result = job.fetch_result() | ||
| job.delete() | ||
| if delete: | ||
| job.delete() | ||
| return result | ||
@@ -453,3 +464,3 @@ | ||
| response = self._session.get('{}/async'.format(self.baseurl), | ||
| response = self._session.get(f'{self.baseurl}/async', | ||
| params=params, | ||
@@ -519,3 +530,3 @@ stream=True) | ||
| headers = {'Content-Type': TABLE_DEF_FORMAT[format]} | ||
| response = self._session.put('{}/tables/{}'.format(self.baseurl, name), | ||
| response = self._session.put(f'{self.baseurl}/tables/{name}', | ||
| headers=headers, | ||
@@ -542,3 +553,3 @@ data=definition) | ||
| response = self._session.delete( | ||
| '{}/tables/{}'.format(self.baseurl, name)) | ||
| f'{self.baseurl}/tables/{name}') | ||
| response.raise_for_status() | ||
@@ -572,3 +583,3 @@ | ||
| response = self._session.post( | ||
| '{}/load/{}'.format(self.baseurl, name), | ||
| f'{self.baseurl}/load/{name}', | ||
| headers=headers, | ||
@@ -597,3 +608,3 @@ data=source) | ||
| result = self._session.post('{}/table-update'.format(self.baseurl), | ||
| result = self._session.post(f'{self.baseurl}/table-update', | ||
| data={'table': table_name, | ||
@@ -658,3 +669,3 @@ 'index': column_name, | ||
| def __init__(self, url, *, session=None): | ||
| def __init__(self, url, *, session=None, delete=True): | ||
| """ | ||
@@ -667,5 +678,10 @@ initialize the job object with the given url and fetch remote values | ||
| the job url | ||
| session : object, optional | ||
| session to use for network requests | ||
| delete : bool, optional | ||
| whether to delete the job when exiting (default: True) | ||
| """ | ||
| self._url = url | ||
| self._session = use_session(session) | ||
| self._delete_on_exit = delete | ||
| self._update() | ||
@@ -681,8 +697,11 @@ | ||
| """ | ||
| Exits the context. The job is silently deleted. | ||
| Exits the context. Unless delete=False was set at initialization, | ||
| the job is deleted. Any deletion errors are silently ignored | ||
| to ensure proper context exit. | ||
| """ | ||
| try: | ||
| self.delete() | ||
| except Exception: | ||
| pass | ||
| if self._delete_on_exit: | ||
| try: | ||
| self.delete() | ||
| except DALServiceError: | ||
| pass | ||
@@ -754,3 +773,3 @@ def _update(self, wait_for_statechange=False, timeout=10.): | ||
| response = self._session.post( | ||
| "{}/executionduration".format(self.url), | ||
| f"{self.url}/executionduration", | ||
| data={"EXECUTIONDURATION": str(value)}) | ||
@@ -788,3 +807,3 @@ response.raise_for_status() | ||
| response = self._session.post( | ||
| "{}/destruction".format(self.url), | ||
| f"{self.url}/destruction", | ||
| data={"DESTRUCTION": value.strftime(IVOA_DATETIME_FORMAT)}) | ||
@@ -828,3 +847,3 @@ response.raise_for_status() | ||
| response = self._session.post( | ||
| '{}/parameters'.format(self.url), | ||
| f'{self.url}/parameters', | ||
| data={"QUERY": query}) | ||
@@ -850,3 +869,3 @@ response.raise_for_status() | ||
| response = self._session.post( | ||
| '{}/parameters'.format(self.url), | ||
| f'{self.url}/parameters', | ||
| data={'UPLOAD': uploads.param()}, | ||
@@ -871,3 +890,3 @@ files=files | ||
| """ | ||
| The job result if exists | ||
| Returns the UWS result with id='result' if it exists, otherwise None. | ||
| """ | ||
@@ -879,3 +898,3 @@ try: | ||
| return self._job.results[0] | ||
| return None | ||
| except IndexError: | ||
@@ -897,3 +916,6 @@ return None | ||
| try: | ||
| uri = self.result.href | ||
| result = self.result | ||
| if result is None: | ||
| return None | ||
| uri = result.href | ||
| if not urlparse(uri).netloc: | ||
@@ -925,3 +947,3 @@ uri = urljoin(self.url, uri) | ||
| response = self._session.post( | ||
| '{}/phase'.format(self.url), data={"PHASE": "RUN"}) | ||
| f'{self.url}/phase', data={"PHASE": "RUN"}) | ||
| response.raise_for_status() | ||
@@ -939,3 +961,3 @@ except requests.RequestException as ex: | ||
| response = self._session.post( | ||
| '{}/phase'.format(self.url), data={"PHASE": "ABORT"}) | ||
| f'{self.url}/phase', data={"PHASE": "ABORT"}) | ||
| response.raise_for_status() | ||
@@ -1024,2 +1046,9 @@ except requests.RequestException as ex: | ||
| """ | ||
| result_uri = self.result_uri | ||
| if result_uri is None: | ||
| self._update() | ||
| self.raise_if_error() | ||
| raise DALServiceError(reason="No result URI available", | ||
| url=self.url) | ||
| try: | ||
@@ -1109,3 +1138,3 @@ response = self._session.get(self.result_uri, stream=True) | ||
| """ | ||
| return '{baseurl}/{mode}'.format(baseurl=self.baseurl, mode=self._mode) | ||
| return f'{self.baseurl}/{self._mode}' | ||
@@ -1112,0 +1141,0 @@ def execute_stream(self, *, post=False): |
@@ -7,2 +7,3 @@ #!/usr/bin/env python | ||
| from functools import partial | ||
| from pathlib import Path | ||
| import re | ||
@@ -14,2 +15,3 @@ import requests_mock | ||
| from pyvo.dal.sia2 import search, SIA2Service, SIA2Query, SIAService, SIAQuery | ||
| from pyvo.dal.exceptions import DALServiceError | ||
@@ -218,1 +220,39 @@ import astropy.units as u | ||
| assert SIA_PARAMETERS_DESC | ||
| def test_none_standardid_capability(): | ||
| """Test that SIA2Service handles capabilities with None standardID.""" | ||
| # Mock a capabilities response with a None standardID | ||
| with requests_mock.Mocker() as m: | ||
| # Mock the capabilities endpoint | ||
| m.get('http://example.com/sia/capabilities', | ||
| content=b'''<?xml version="1.0" encoding="UTF-8"?> | ||
| <vosi:capabilities xmlns:vosi="http://www.ivoa.net/xml/VOSICapabilities/v1.0"> | ||
| <capability> | ||
| <!-- This capability has no standardID attribute --> | ||
| <interface> | ||
| <accessURL use="full">http://example.com/sia/query</accessURL> | ||
| </interface> | ||
| </capability> | ||
| <capability standardID="ivo://ivoa.net/std/SIA#query-2.0"> | ||
| <interface> | ||
| <accessURL use="full">http://example.com/sia/query</accessURL> | ||
| </interface> | ||
| </capability> | ||
| </vosi:capabilities>''') | ||
| # This should not raise an AttributeError | ||
| sia2_service = SIA2Service('http://example.com/sia') | ||
| # Basic verification that the service was created successfully | ||
| assert sia2_service is not None | ||
| assert sia2_service.query_ep is not None | ||
| def test_url_is_not_sia2(): | ||
| # with capabilities from an other service type, we raise an error | ||
| with open(Path(__file__).parent / "data/tap/capabilities.xml", "rb") as f: | ||
| with requests_mock.Mocker() as mocker: | ||
| mocker.get("http://example.com/sia/capabilities", content=f.read()) | ||
| with pytest.raises(DALServiceError, | ||
| match="This URL does not seem to correspond to an " | ||
| "SIA2 service."): | ||
| SIA2Service('http://example.com/sia') |
@@ -10,2 +10,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from io import BytesIO, StringIO | ||
| from unittest.mock import Mock | ||
| from urllib.parse import parse_qsl | ||
@@ -139,3 +140,6 @@ import tempfile | ||
| def validator(self, request): | ||
| pass | ||
| data = dict(parse_qsl(request.body)) | ||
| if 'QUERY' in data: | ||
| if "select" not in data['QUERY'].casefold(): | ||
| raise DALQueryError("Missing select") | ||
@@ -204,3 +208,3 @@ def use(self, mocker): | ||
| context.headers['Location'] = ( | ||
| 'http://example.com/tap/async/{}'.format(newid)) | ||
| f'http://example.com/tap/async/{newid}') | ||
@@ -286,3 +290,3 @@ self._jobs[newid] = job | ||
| param.content = ';'.join([ | ||
| '{}={}'.format(key, value) for key, value | ||
| f'{key}={value}' for key, value | ||
| in uploads1.items() | ||
@@ -364,2 +368,8 @@ ]) | ||
| @pytest.fixture() | ||
| def async_fixture_with_timeout(mocker): | ||
| mock_server = MockAsyncTAPServer() | ||
| yield from mock_server.use(mocker) | ||
| @pytest.fixture() | ||
| def tables(mocker): | ||
@@ -541,8 +551,25 @@ def callback_tables(request, context): | ||
| @pytest.mark.filterwarnings("ignore::astropy.io.votable.exceptions.W06") | ||
| def test_run_async(self): | ||
| def test_run_async(self, monkeypatch): | ||
| service = TAPService('http://example.com/tap') | ||
| results = service.run_async("SELECT * FROM ivoa.obscore") | ||
| mock_delete = Mock() | ||
| monkeypatch.setattr(AsyncTAPJob, "delete", mock_delete) | ||
| results = service.run_async("SELECT * FROM ivoa.obscore", delete=False) | ||
| _test_image_results(results) | ||
| # make sure that delete was not called | ||
| mock_delete.assert_not_called() | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| @pytest.mark.filterwarnings("ignore::astropy.io.votable.exceptions.W27") | ||
| @pytest.mark.filterwarnings("ignore::astropy.io.votable.exceptions.W48") | ||
| @pytest.mark.filterwarnings("ignore::astropy.io.votable.exceptions.W06") | ||
| def test_run_async_on_error(self, monkeypatch): | ||
| service = TAPService('http://example.com/tap') | ||
| mock_delete = Mock() | ||
| monkeypatch.setattr(AsyncTAPJob, "delete", mock_delete) | ||
| with pytest.raises(DALQueryError): | ||
| service.run_async("bad query", delete=True) | ||
| # make sure that the job is deleted even with a bad query | ||
| mock_delete.assert_called_once() | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| def test_submit_job(self): | ||
@@ -748,2 +775,99 @@ service = TAPService('http://example.com/tap') | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| def test_job_no_result(self): | ||
| service = TAPService('http://example.com/tap') | ||
| job = service.submit_job("SELECT * FROM ivoa.obscore") | ||
| with pytest.raises(DALServiceError) as excinfo: | ||
| job.fetch_result() | ||
| assert "No result URI available" in str(excinfo.value) | ||
| job.delete() | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| def test_fetch_result_network_error(self): | ||
| service = TAPService('http://example.com/tap') | ||
| job = service.submit_job("SELECT * FROM ivoa.obscore") | ||
| job.run() | ||
| job.wait() | ||
| status_response = '''<?xml version="1.0" encoding="UTF-8"?> | ||
| <uws:job xmlns:uws="http://www.ivoa.net/xml/UWS/v1.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <uws:jobId>1</uws:jobId> | ||
| <uws:phase>COMPLETED</uws:phase> | ||
| <uws:results> | ||
| <uws:result id="result" xsi:type="vot:VOTable" | ||
| href="http://example.com/tap/async/1/results/result"/> | ||
| </uws:results> | ||
| </uws:job>''' | ||
| with requests_mock.Mocker() as rm: | ||
| rm.get(f'http://example.com/tap/async/{job.job_id}', | ||
| text=status_response) | ||
| rm.get( | ||
| f'http://example.com/tap/async/{job.job_id}/results/result', | ||
| exc=requests.exceptions.ConnectTimeout | ||
| ) | ||
| with pytest.raises(DALServiceError) as excinfo: | ||
| job.fetch_result() | ||
| assert "Unknown service error" in str(excinfo.value) | ||
| job.delete() | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| def test_job_no_result_uri(self): | ||
| status_response = '''<?xml version="1.0" encoding="UTF-8"?> | ||
| <uws:job xmlns:uws="http://www.ivoa.net/xml/UWS/v1.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <uws:jobId>1</uws:jobId> | ||
| <uws:phase>COMPLETED</uws:phase> | ||
| <uws:results> | ||
| <uws:result id="diag" xlink:href="uws:executing:10"/> | ||
| </uws:results> | ||
| </uws:job>''' | ||
| service = TAPService('http://example.com/tap') | ||
| job = service.submit_job("SELECT * FROM ivoa.obscore") | ||
| job.run() | ||
| job.wait() | ||
| with requests_mock.Mocker() as rm: | ||
| rm.get(f'http://example.com/tap/async/{job.job_id}', | ||
| text=status_response) | ||
| job._update() | ||
| with pytest.raises(DALServiceError) as excinfo: | ||
| job.fetch_result() | ||
| assert "No result URI available" in str(excinfo.value) | ||
| job.delete() | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| def test_job_with_empty_error(self): | ||
| error_response = '''<?xml version="1.0" encoding="UTF-8"?> | ||
| <uws:job xmlns:uws="http://www.ivoa.net/xml/UWS/v1.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <uws:jobId>1</uws:jobId> | ||
| <uws:phase>ERROR</uws:phase> | ||
| <uws:results/> | ||
| <uws:errorSummary> | ||
| <uws:message></uws:message> | ||
| </uws:errorSummary> | ||
| </uws:job>''' | ||
| service = TAPService('http://example.com/tap') | ||
| job = service.submit_job("SELECT * FROM ivoa.obscore") | ||
| job.run() | ||
| job.wait() | ||
| with requests_mock.Mocker() as rm: | ||
| rm.get(f'http://example.com/tap/async/{job.job_id}', | ||
| text=error_response) | ||
| job._update() | ||
| with pytest.raises(DALQueryError) as excinfo: | ||
| job.fetch_result() | ||
| assert "<No useful error from server>" in str(excinfo.value) | ||
| @pytest.mark.usefixtures('async_fixture') | ||
| def test_endpoint_503_with_retry_after(self): | ||
@@ -837,3 +961,3 @@ service = TAPService('http://example.com/tap') | ||
| "ivo://ivoa.net/std/TAPRegExt#features-adqlgeo") | ||
| assert set(f.form for f in features) == { | ||
| assert {f.form for f in features} == { | ||
| 'CENTROID', 'CONTAINS', 'COORD1', 'POLYGON', | ||
@@ -840,0 +964,0 @@ 'INTERSECTS', 'COORD2', 'BOX', 'AREA', 'DISTANCE', |
+2
-2
@@ -190,3 +190,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| tables_urls = [ | ||
| '{}/tables'.format(self.baseurl), | ||
| f'{self.baseurl}/tables', | ||
| url_sibling(self.baseurl, 'tables') | ||
@@ -245,3 +245,3 @@ ] | ||
| if not table.columns and not table.foreignkeys: | ||
| tables_url = '{}/{}'.format(self._endpoint_url, name) | ||
| tables_url = f'{self._endpoint_url}/{name}' | ||
| response = self._get_table_file(tables_url) | ||
@@ -248,0 +248,0 @@ |
+21
-19
@@ -39,3 +39,4 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| # imports for type hints | ||
| from typing import Callable, Generator, List, Optional, Set, Tuple | ||
| from typing import Callable, Optional | ||
| from collections.abc import Generator | ||
| from astropy.units import quantity | ||
@@ -70,2 +71,3 @@ | ||
| """ | ||
| def __init__(self, res_rec): | ||
@@ -83,3 +85,3 @@ self.res_rec = res_rec | ||
| @functools.lru_cache(maxsize=None) | ||
| @functools.cache | ||
| def obscore_column_names(): | ||
@@ -158,3 +160,3 @@ """returns the names of obscore columns. | ||
| def _clean_for(records: List[Queriable], ivoids_to_remove: Set[str]): | ||
| def _clean_for(records: list[Queriable], ivoids_to_remove: set[str]): | ||
| """returns the Queriables in records the ivoids of which are | ||
@@ -217,6 +219,6 @@ not in ivoids_to_remove. | ||
| self.already_queried, self.failed_services = 0, 0 | ||
| self.results: List[obscore.ObsCoreMetadata] = [] | ||
| self.results: list[obscore.ObsCoreMetadata] = [] | ||
| self.watcher = watcher | ||
| self.log_messages: List[str] = [] | ||
| self.known_access_urls: Set[str] = set() | ||
| self.log_messages: list[str] = [] | ||
| self.known_access_urls: set[str] = set() | ||
@@ -247,3 +249,3 @@ self._service_list_lock = threading.Lock() | ||
| def ids(recs): | ||
| return set(r.ivoid for r in recs) | ||
| return {r.ivoid for r in recs} | ||
@@ -281,3 +283,3 @@ self.sia1_recs = _clean_for(self.sia1_recs, | ||
| collections_to_remove = set(r["ivoid"] for r in services_for) | ||
| collections_to_remove = {r["ivoid"] for r in services_for} | ||
| self.sia1_recs = _clean_for(self.sia1_recs, collections_to_remove) | ||
@@ -305,8 +307,8 @@ self.sia2_recs = _clean_for(self.sia2_recs, collections_to_remove) | ||
| for rec in obscore_services: | ||
| new_style_access_urls |= set( | ||
| i.access_url for i in rec.list_interfaces("tap")) | ||
| new_style_access_urls |= { | ||
| i.access_url for i in rec.list_interfaces("tap")} | ||
| for tap_rec in tap_services_with_obscore: | ||
| access_urls = set( | ||
| i.baseurl for i in rec.list_services("tap")) | ||
| access_urls = { | ||
| i.baseurl for i in rec.list_services("tap")} | ||
| if new_style_access_urls.isdisjoint(access_urls): | ||
@@ -345,7 +347,7 @@ obscore_services.append(obscore_services) | ||
| registry.Servicetype("sia"), *constraints)] | ||
| self._info("Found {} SIA1 service(s)".format(len(self.sia1_recs))) | ||
| self._info(f"Found {len(self.sia1_recs)} SIA1 service(s)") | ||
| self.sia2_recs = [Queriable(r) for r in registry.search( | ||
| registry.Servicetype("sia2"), *constraints)] | ||
| self._info("Found {} SIA2 service(s)".format(len(self.sia2_recs))) | ||
| self._info(f"Found {len(self.sia2_recs)} SIA2 service(s)") | ||
@@ -448,3 +450,3 @@ self.obscore_recs = self._discover_obscore_services(*constraints) | ||
| self._info("Querying SIA1 {}...".format(rec.title)) | ||
| self._info(f"Querying SIA1 {rec.title}...") | ||
| svc = rec.res_rec.get_service("sia", session=self.session, lax=True) | ||
@@ -484,3 +486,3 @@ n_found = self._add_records( | ||
| """ | ||
| self._info("Querying SIA2 {}...".format(rec.title)) | ||
| self._info(f"Querying SIA2 {rec.title}...") | ||
@@ -519,3 +521,3 @@ svc = rec.res_rec.get_service("sia2", session=self.session, lax=True) | ||
| """ | ||
| self._info("Querying Obscore {}...".format(rec.title)) | ||
| self._info(f"Querying Obscore {rec.title}...") | ||
| svc = rec.res_rec.get_service("tap", session=self.session, lax=True) | ||
@@ -590,3 +592,3 @@ | ||
| *, | ||
| space: Optional[Tuple[float, float, float]] = None, | ||
| space: Optional[tuple[float, float, float]] = None, | ||
| spectrum: Optional[quantity.Quantity] = None, | ||
@@ -598,3 +600,3 @@ time: Optional[time.Time] = None, | ||
| services: Optional[registry.RegistryResults] = None)\ | ||
| -> Tuple[List[obscore.ObsCoreMetadata], List[str]]: | ||
| -> tuple[list[obscore.ObsCoreMetadata], list[str]]: | ||
| """returns a collection of ObsCoreMetadata-s matching certain constraints | ||
@@ -601,0 +603,0 @@ and a list of log lines. |
@@ -108,3 +108,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| assert set(queriable.search_kwargs) == set(["time"]) | ||
| assert set(queriable.search_kwargs) == {"time"} | ||
| assert abs(queriable.search_kwargs["time"][0].utc.value | ||
@@ -119,3 +119,3 @@ - 40872.54166667) < 1e-8 | ||
| assert set(queriable.search_kwargs) == set(["time"]) | ||
| assert set(queriable.search_kwargs) == {"time"} | ||
| assert abs(queriable.search_kwargs["time"][0].utc.value | ||
@@ -122,0 +122,0 @@ - 40872.54166667) < 1e-8 |
@@ -30,3 +30,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| raise ValueError('Cannot parse datetime {}'.format(val)) | ||
| raise ValueError(f'Cannot parse datetime {val}') | ||
@@ -33,0 +33,0 @@ |
@@ -325,3 +325,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| return table | ||
| raise KeyError("No table with name {} found".format(name)) | ||
| raise KeyError(f"No table with name {name} found") | ||
@@ -328,0 +328,0 @@ |
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| # -*- coding: utf-8 -*- | ||
| """ | ||
@@ -29,4 +28,4 @@ .. _warnings: | ||
| __all__ = ["VOSIWarning"] | ||
| __all__ += ["W{:0>2}".format(i) for i in range(1, 36)] | ||
| __all__ += ["E{:0>2}".format(i) for i in range(1, 10)] | ||
| __all__ += [f"W{i:0>2}" for i in range(1, 36)] | ||
| __all__ += [f"E{i:0>2}" for i in range(1, 10)] | ||
@@ -33,0 +32,0 @@ |
@@ -42,3 +42,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| print("Datamodel {}".format(self.content)) | ||
| print(f"Datamodel {self.content}") | ||
| print(indent(self.ivo_id, INDENT)) | ||
@@ -75,3 +75,3 @@ print() | ||
| """ | ||
| print('Output format {}'.format(self.mime)) | ||
| print(f'Output format {self.mime}') | ||
@@ -105,3 +105,3 @@ if self.aliases: | ||
| def __repr__(self): | ||
| return '<UploadMethod ivo-id="{}"/>'.format(self.ivo_id) | ||
| return f'<UploadMethod ivo-id="{self.ivo_id}"/>' | ||
@@ -238,3 +238,3 @@ def describe(self): | ||
| def __repr__(self): | ||
| return '<Language>{}</Language>'.format(self.name) | ||
| return f'<Language>{self.name}</Language>' | ||
@@ -245,3 +245,3 @@ def describe(self): | ||
| """ | ||
| print("Language {}".format(self.name)) | ||
| print(f"Language {self.name}") | ||
@@ -481,5 +481,5 @@ for languagefeaturelist in self.languagefeaturelists: | ||
| print("Time a job is kept (in seconds)") | ||
| print(indent("Default {}".format(self.retentionperiod.default), INDENT)) | ||
| print(indent(f"Default {self.retentionperiod.default}", INDENT)) | ||
| if self.retentionperiod.hard: | ||
| print(indent("Maximum {}".format(self.retentionperiod.hard), INDENT)) | ||
| print(indent(f"Maximum {self.retentionperiod.hard}", INDENT)) | ||
| print() | ||
@@ -489,5 +489,5 @@ | ||
| print("Maximal run time of a job") | ||
| print(indent("Default {}".format(self.executionduration.default), INDENT)) | ||
| print(indent(f"Default {self.executionduration.default}", INDENT)) | ||
| if self.executionduration.hard: | ||
| print(indent("Maximum {}".format(self.executionduration.hard), INDENT)) | ||
| print(indent(f"Maximum {self.executionduration.hard}", INDENT)) | ||
| print() | ||
@@ -494,0 +494,0 @@ |
@@ -175,4 +175,3 @@ #!/usr/bin/env python | ||
| def test_udfs(self, parsed_minimal_tapregext): | ||
| assert parsed_minimal_tapregext[2].get_adql( | ||
| ).languagefeaturelists == [] | ||
| assert parsed_minimal_tapregext[2].get_adql().languagefeaturelists == [] | ||
@@ -179,0 +178,0 @@ def test_uploadmethods(self, parsed_minimal_tapregext): |
@@ -496,3 +496,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| def __repr__(self): | ||
| return '<BaseParam name="{}"/>'.format(self.name) | ||
| return f'<BaseParam name="{self.name}"/>' | ||
@@ -499,0 +499,0 @@ @xmlelement(plain=True, multiple_exc=W05) |
@@ -242,3 +242,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| print('Interface {}'.format(self._xsi_type)) | ||
| print(f'Interface {self._xsi_type}') | ||
@@ -374,3 +374,3 @@ accessurls = '\n'.join( | ||
| """ | ||
| print("Capability {}".format(self.standardid)) | ||
| print(f"Capability {self.standardid}") | ||
| print() | ||
@@ -377,0 +377,0 @@ |
@@ -1,2 +0,1 @@ | ||
| # package entry point | ||
| from .viewer.mivot_viewer import MivotViewer | ||
| # Licensed under a 3-clause BSD style license - see LICENSE.rst |
@@ -22,3 +22,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| RADIAL_VELOCITY = "radialVelocity" | ||
| EPOCH = "epoch" | ||
| EPOCH = "obsDate" | ||
| FRAME = "frame" | ||
@@ -41,3 +41,3 @@ EQUINOX = "equinox" | ||
| class SkyCoordBuilder(object): | ||
| class SkyCoordBuilder: | ||
| ''' | ||
@@ -99,6 +99,14 @@ Utility generating SkyCoord instances from MIVOT annotations | ||
| ------- | ||
| string | ||
| string or None | ||
| attribute value formatted as [scale]year | ||
| """ | ||
| scale = "J" if not besselian else "B" | ||
| # Process complex type "mango:DateTime | ||
| # only "year" representation are supported yet | ||
| if hk_field['dmtype'] == "mango:DateTime": | ||
| representation = hk_field['representation']['value'] | ||
| timestamp = hk_field['dateTime']['value'] | ||
| if representation == "year": | ||
| return f"{scale}{timestamp}" | ||
| return None | ||
| return (f"{scale}{hk_field['value']}" if hk_field["unit"] in ("yr", "year") | ||
@@ -124,3 +132,3 @@ else hk_field["value"]) | ||
| """ | ||
| coo_sys = self._mivot_instance_dict["coordSys"] | ||
| coo_sys = self._mivot_instance_dict["spaceSys"]["frame"] | ||
| equinox = None | ||
@@ -127,0 +135,0 @@ frame = coo_sys["spaceRefFrame"]["value"].lower() |
@@ -48,14 +48,6 @@ """ | ||
| target = annotation_seeker.get_globals_instance_by_dmid(dmref) | ||
| found_in_global = True | ||
| if target is None and templates_ref is not None: | ||
| target = annotation_seeker.get_templates_instance_by_dmid(templates_ref, dmref) | ||
| found_in_global = False | ||
| if target is None: | ||
| raise MivotError(f"Cannot resolve reference={dmref}") | ||
| # Resolve static references recursively | ||
| if not found_in_global: | ||
| StaticReferenceResolver.resolve(annotation_seeker, templates_ref, ele) | ||
| else: | ||
| StaticReferenceResolver.resolve(annotation_seeker, None, ele) | ||
| # Set the reference role to the copied instance | ||
| target_copy = deepcopy(target) | ||
@@ -62,0 +54,0 @@ # If the reference is within a collection: no role |
| """ | ||
| ``seekers`` package contains utilities for retrieving | ||
| ``seekers`` package contains utilities for retrieving | ||
| components of VOTales or of Mivot blocks | ||
| """ |
@@ -1,222 +0,363 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <VOTABLE version="1.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xmlns="http://www.ivoa.net/xml/VOTable/v1.3" | ||
| xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/v1.3"> | ||
| <RESOURCE ID="yCat_1329" name="I/329"> | ||
| <DESCRIPTION>URAT1 Catalog (Zacharias+ 2015)</DESCRIPTION> <INFO name="ivoid" value="ivo://cds.vizier/i/329"> IVOID of underlying data collection </INFO> | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <!-- Produced with astropy.io.votable version 6.0.0 | ||
| http://www.astropy.org/ --> | ||
| <VOTABLE version="1.4" xmlns="http://www.ivoa.net/xml/VOTable/v1.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ivoa.net/xml/VOTable/v1.3 http://www.ivoa.net/xml/VOTable/VOTable-1.4.xsd"> | ||
| <RESOURCE ID="yCat_1329" type="results"> | ||
| <DESCRIPTION> | ||
| URAT1 Catalog (Zacharias+ 2015) | ||
| </DESCRIPTION> | ||
| <COOSYS ID="H" system="ICRS"/> | ||
| <TIMESYS ID="time_1" refposition="UNKNOWN" timeorigin="0.000000" timescale="UNKNOWN"/> | ||
| <TABLE ID="I_329_urat1" name="I/329/urat1"> | ||
| <DESCRIPTION>URAT1 catalog</DESCRIPTION> | ||
| <!-- RowName: -c=${$poseq}&-c.rs=0.004 --> | ||
| <!-- Definitions of GROUPs and FIELDs --> | ||
| <FIELD name="_r" ucd="pos.angDistance" datatype="double" width="8" precision="6" unit=""><!-- ucd="POS_ANG_DIST_GENERAL" --> | ||
| <DESCRIPTION>Distance from center (052.2670800+59.9402700)[ICRS], at Epoch of catalog (Epoch)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="URAT1" ucd="meta.id;meta.main" datatype="char" arraysize="10*"><!-- ucd="meta.id;meta.main" --> | ||
| <DESCRIPTION>URAT1 recommended identifier (ZZZ-NNNNNN) (13) [datatype=char]</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="RAICRS" ucd="pos.eq.ra;meta.main" ref="H" datatype="double" width="11" precision="7" unit="deg"><!-- ucd="pos.eq.ra;meta.main" --> | ||
| <DESCRIPTION>Right ascension on ICRS, at "Epoch" (1)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="DEICRS" ucd="pos.eq.dec;meta.main" ref="H" datatype="double" width="11" precision="7" unit="deg"><!-- ucd="pos.eq.dec;meta.main" --> | ||
| <DESCRIPTION>Declination on ICRS, at "Epoch" (1)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="sigs" ucd="stat.error" datatype="short" width="3" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>Position error per coordinate, from scatter (2)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="sigm" ucd="stat.error" datatype="short" width="3" unit="mas"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>Position error per coordinate, from model (2)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Ns" ucd="meta.number" datatype="short" width="2"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(nst) Total number of sets the star is in (3)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Nu" ucd="meta.number" datatype="short" width="2"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(nsu) Number of sets used for mean position (3)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Epoch" ucd="time.epoch;obs;stat.mean" ref="H" ID="_tab1_8" datatype="double" width="8" precision="3" unit="yr"><!-- ucd="TIME_EPOCH" --> | ||
| <DESCRIPTION>(epoc) Mean URAT observation epoch (1)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="f.mag" ucd="phot.mag;em.opt.R" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_MAG_OPTICAL" --> | ||
| <DESCRIPTION>?(mmag) mean URAT model fit magnitude (4)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_f.mag" ucd="stat.error" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(sigp) URAT photometry error (5)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="Nm" ucd="meta.number" datatype="short" width="2"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(nsm) Number of sets used for URAT magnitude (3)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="r" ucd="meta.code" datatype="unsignedByte" width="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>(ref) largest reference star flag (6)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Nit" ucd="meta.number" datatype="short" width="3"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(nit) Total number of images (observations)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Niu" ucd="meta.number" datatype="short" width="3"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(niu) Number of images used for mean position</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Ngt" ucd="meta.number" datatype="short" width="3"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(ngt) Total number of 1st order grating observations</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Ngu" ucd="meta.number" datatype="short" width="3"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(ngu) Number of 1st order grating positions used</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="pmRA" ucd="pos.pm;pos.eq.ra" ref="H" datatype="float" width="6" precision="1" unit="mas/yr"><!-- ucd="POS_EQ_PMRA" --> | ||
| <DESCRIPTION>?(pmr) Proper motion RA*cosDec (from 2MASS) (7)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="pmDE" ucd="pos.pm;pos.eq.dec" ref="H" datatype="float" width="6" precision="1" unit="mas/yr"><!-- ucd="POS_EQ_PMDEC" --> | ||
| <DESCRIPTION>?(pmd) Proper motion in Declination (7)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_pm" ucd="stat.error" datatype="float" width="4" precision="1" unit="mas/yr"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(pme) Proper motion error per coordinate (8)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="mf2" ucd="meta.code" datatype="short" width="2"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[1/11] Match flag URAT with 2MASS (9)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="mfa" ucd="meta.code" datatype="short" width="2"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[1/11] Match flag URAT with APASS (9)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="G" ucd="meta.code" datatype="char" arraysize="1"><!-- ucd="CODE_MISC" --> | ||
| <DESCRIPTION>[-] "-" if there is no match with GSC2.4 (14)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="2Mkey" ID="_2Mkey" ucd="meta.id" datatype="long" width="10"><!-- ucd="ID_NUMBER" --> | ||
| <DESCRIPTION>?(id2) unique 2MASS star identification number</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="-9223372036854775808" /> | ||
| </FIELD> | ||
| <FIELD name="Jmag" ucd="phot.mag;em.IR.J" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_JHN_J" --> | ||
| <DESCRIPTION>?(jmag) 2MASS J-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Jmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(ejmag) Error on Jmag</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="q_Jmag" ucd="meta.code.qual" datatype="char" arraysize="2"><!-- ucd="CODE_QUALITY" --> | ||
| <DESCRIPTION>[0,58]? J-band quality-confusion flag (10)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Hmag" ucd="phot.mag;em.IR.H" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_JHN_H" --> | ||
| <DESCRIPTION>?(hmag) 2MASS H-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Hmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(ehmag) Error on H-band magnitude (10)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="q_Hmag" ucd="meta.code.qual" datatype="char" arraysize="2"><!-- ucd="CODE_QUALITY" --> | ||
| <DESCRIPTION>[0,58]? H-band quality-confusion flag (10)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Kmag" ucd="phot.mag;em.IR.K" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_JHN_K" --> | ||
| <DESCRIPTION>?(kmag) 2MASS Ks-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Kmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(ekmag) Error on Ks-band magnitude (10)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="q_Kmag" ucd="meta.code.qual" datatype="char" arraysize="2"><!-- ucd="CODE_QUALITY" --> | ||
| <DESCRIPTION>[0,58]? Ks-band quality-confusion flag (10)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Nn" ucd="meta.number" datatype="short" width="3"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(ann) Number of APASS observation nights (12)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="No" ucd="meta.number" datatype="short" width="3"><!-- ucd="NUMBER" --> | ||
| <DESCRIPTION>(ano) Number of APASS observations (12)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| </FIELD> | ||
| <FIELD name="Bmag" ucd="phot.mag;em.opt.B" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_MAG_B" --> | ||
| <DESCRIPTION>?(abm) APASS B-band magnitude (11)</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Bmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(ebm) Error on Bmag</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="Vmag" ucd="phot.mag;em.opt.V" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_MAG_V" --> | ||
| <DESCRIPTION>?(avm) APASS V-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_Vmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(evm) Error on Vmag</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="gmag" ucd="phot.mag;em.opt.B" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_SDSS_G" --> | ||
| <DESCRIPTION>?(agm) APASS g-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_gmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(egm) Error on gmag</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="rmag" ucd="phot.mag;em.opt.R" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_SDSS_R" --> | ||
| <DESCRIPTION>?(arm) APASS r-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_rmag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(erm) Error on rmag</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="imag" ucd="phot.mag;em.opt.I" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="PHOT_SDSS_I" --> | ||
| <DESCRIPTION>?(aim) APASS i-band magnitude</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <FIELD name="e_imag" ucd="stat.error;phot.mag" datatype="float" width="6" precision="3" unit="mag"><!-- ucd="ERROR" --> | ||
| <DESCRIPTION>?(eim) Error on imag</DESCRIPTION> | ||
| <!-- ++++ What is 'M' in edition ?? --> | ||
| <VALUES null="NaN" /> | ||
| </FIELD> | ||
| <DATA><TABLEDATA> | ||
| <TR><TD>0.049402</TD><TD>750-146023</TD><TD>052.2340018</TD><TD>+59.8937333</TD><TD>9</TD><TD>6</TD><TD>13</TD><TD>13</TD><TD>2013.418</TD><TD>15.340</TD><TD>0.013</TD><TD>13</TD><TD>9</TD><TD>74</TD><TD>74</TD><TD>0</TD><TD>0</TD><TD>1.5</TD><TD>-12.3</TD><TD>5.9</TD><TD>1</TD><TD>5</TD><TD></TD><TD>758808681</TD><TD>13.713</TD><TD>0.028</TD><TD>5</TD><TD>13.340</TD><TD>0.034</TD><TD>5</TD><TD>13.101</TD><TD>0.034</TD><TD>5</TD><TD>1</TD><TD>4</TD><TD>17.632</TD><TD>0.204</TD><TD>16.164</TD><TD>0.001</TD><TD>16.690</TD><TD>0.001</TD><TD>15.750</TD><TD>0.001</TD><TD></TD><TD></TD></TR> | ||
| </TABLEDATA></DATA> | ||
| </TABLE> | ||
| </RESOURCE> | ||
| <TIMESYS ID="time_1" refposition="UNKNOWN" timeorigin="0.0" timescale="UNKNOWN"/> | ||
| <INFO ID="ivoid" name="ivoid" value="ivo://cds.vizier/i/329">IVOID of underlying data collection</INFO> | ||
| <TABLE ID="I_329_urat1" name="I/329/urat1" nrows="1"> | ||
| <DESCRIPTION> | ||
| URAT1 catalog | ||
| </DESCRIPTION> | ||
| <FIELD ID="_r" datatype="double" name="_r" precision="6" ucd="pos.angDistance" unit="---" width="8"> | ||
| <DESCRIPTION> | ||
| Distance from center (052.2670800+59.9402700)[ICRS], at Epoch of | ||
| catalog (Epoch) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="URAT1" arraysize="10" datatype="char" name="URAT1" ucd="meta.id;meta.main"> | ||
| <DESCRIPTION> | ||
| URAT1 recommended identifier (ZZZ-NNNNNN) (13) [datatype=char] | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="RAICRS" datatype="double" name="RAICRS" precision="7" ref="H" ucd="pos.eq.ra;meta.main" unit="deg" width="11"> | ||
| <DESCRIPTION> | ||
| Right ascension on ICRS, at "Epoch" (1) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="DEICRS" datatype="double" name="DEICRS" precision="7" ref="H" ucd="pos.eq.dec;meta.main" unit="deg" width="11"> | ||
| <DESCRIPTION> | ||
| Declination on ICRS, at "Epoch" (1) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="sigs" datatype="short" name="sigs" ucd="stat.error" unit="mas" width="3"> | ||
| <DESCRIPTION> | ||
| Position error per coordinate, from scatter (2) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="sigm" datatype="short" name="sigm" ucd="stat.error" unit="mas" width="3"> | ||
| <DESCRIPTION> | ||
| Position error per coordinate, from model (2) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Ns" datatype="short" name="Ns" ucd="meta.number" width="2"> | ||
| <DESCRIPTION> | ||
| (nst) Total number of sets the star is in (3) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Nu" datatype="short" name="Nu" ucd="meta.number" width="2"> | ||
| <DESCRIPTION> | ||
| (nsu) Number of sets used for mean position (3) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="_tab1_8" datatype="double" name="Epoch" precision="3" ref="H" ucd="time.epoch;obs;stat.mean" unit="yr" width="8"> | ||
| <DESCRIPTION> | ||
| (epoc) Mean URAT observation epoch (1) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="f.mag" datatype="float" name="f.mag" precision="3" ucd="phot.mag;em.opt.R" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(mmag) mean URAT model fit magnitude (4) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_f.mag" datatype="float" name="e_f.mag" precision="3" ucd="stat.error" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(sigp) URAT photometry error (5) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="Nm" datatype="short" name="Nm" ucd="meta.number" width="2"> | ||
| <DESCRIPTION> | ||
| (nsm) Number of sets used for URAT magnitude (3) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="r" datatype="unsignedByte" name="r" ucd="meta.code" width="1"> | ||
| <DESCRIPTION> | ||
| (ref) largest reference star flag (6) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Nit" datatype="short" name="Nit" ucd="meta.number" width="3"> | ||
| <DESCRIPTION> | ||
| (nit) Total number of images (observations) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Niu" datatype="short" name="Niu" ucd="meta.number" width="3"> | ||
| <DESCRIPTION> | ||
| (niu) Number of images used for mean position | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Ngt" datatype="short" name="Ngt" ucd="meta.number" width="3"> | ||
| <DESCRIPTION> | ||
| (ngt) Total number of 1st order grating observations | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Ngu" datatype="short" name="Ngu" ucd="meta.number" width="3"> | ||
| <DESCRIPTION> | ||
| (ngu) Number of 1st order grating positions used | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="pmRA" datatype="float" name="pmRA" precision="1" ref="H" ucd="pos.pm;pos.eq.ra" unit="mas.yr-1" width="6"> | ||
| <DESCRIPTION> | ||
| ?(pmr) Proper motion RA*cosDec (from 2MASS) (7) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="pmDE" datatype="float" name="pmDE" precision="1" ref="H" ucd="pos.pm;pos.eq.dec" unit="mas.yr-1" width="6"> | ||
| <DESCRIPTION> | ||
| ?(pmd) Proper motion in Declination (7) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_pm" datatype="float" name="e_pm" precision="1" ucd="stat.error" unit="mas.yr-1" width="4"> | ||
| <DESCRIPTION> | ||
| ?(pme) Proper motion error per coordinate (8) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="mf2" datatype="short" name="mf2" ucd="meta.code" width="2"> | ||
| <DESCRIPTION> | ||
| [1/11] Match flag URAT with 2MASS (9) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="mfa" datatype="short" name="mfa" ucd="meta.code" width="2"> | ||
| <DESCRIPTION> | ||
| [1/11] Match flag URAT with APASS (9) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="G" arraysize="1" datatype="char" name="G" ucd="meta.code"> | ||
| <DESCRIPTION> | ||
| [-] "-" if there is no match with GSC2.4 (14) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="_2Mkey" datatype="long" name="2Mkey" ucd="meta.id" width="10"> | ||
| <DESCRIPTION> | ||
| ?(id2) unique 2MASS star identification number | ||
| </DESCRIPTION> | ||
| <VALUES null="-9223372036854775808"/> | ||
| </FIELD> | ||
| <FIELD ID="Jmag" datatype="float" name="Jmag" precision="3" ucd="phot.mag;em.IR.J" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(jmag) 2MASS J-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_Jmag" datatype="float" name="e_Jmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(ejmag) Error on Jmag | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="q_Jmag" arraysize="2" datatype="char" name="q_Jmag" ucd="meta.code.qual"> | ||
| <DESCRIPTION> | ||
| [0,58]? J-band quality-confusion flag (10) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Hmag" datatype="float" name="Hmag" precision="3" ucd="phot.mag;em.IR.H" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(hmag) 2MASS H-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_Hmag" datatype="float" name="e_Hmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(ehmag) Error on H-band magnitude (10) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="q_Hmag" arraysize="2" datatype="char" name="q_Hmag" ucd="meta.code.qual"> | ||
| <DESCRIPTION> | ||
| [0,58]? H-band quality-confusion flag (10) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Kmag" datatype="float" name="Kmag" precision="3" ucd="phot.mag;em.IR.K" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(kmag) 2MASS Ks-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_Kmag" datatype="float" name="e_Kmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(ekmag) Error on Ks-band magnitude (10) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="q_Kmag" arraysize="2" datatype="char" name="q_Kmag" ucd="meta.code.qual"> | ||
| <DESCRIPTION> | ||
| [0,58]? Ks-band quality-confusion flag (10) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Nn" datatype="short" name="Nn" ucd="meta.number" width="3"> | ||
| <DESCRIPTION> | ||
| (ann) Number of APASS observation nights (12) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="No" datatype="short" name="No" ucd="meta.number" width="3"> | ||
| <DESCRIPTION> | ||
| (ano) Number of APASS observations (12) | ||
| </DESCRIPTION> | ||
| </FIELD> | ||
| <FIELD ID="Bmag" datatype="float" name="Bmag" precision="3" ucd="phot.mag;em.opt.B" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(abm) APASS B-band magnitude (11) | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_Bmag" datatype="float" name="e_Bmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(ebm) Error on Bmag | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="Vmag" datatype="float" name="Vmag" precision="3" ucd="phot.mag;em.opt.V" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(avm) APASS V-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_Vmag" datatype="float" name="e_Vmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(evm) Error on Vmag | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="gmag" datatype="float" name="gmag" precision="3" ucd="phot.mag;em.opt.B" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(agm) APASS g-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_gmag" datatype="float" name="e_gmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(egm) Error on gmag | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="rmag" datatype="float" name="rmag" precision="3" ucd="phot.mag;em.opt.R" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(arm) APASS r-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_rmag" datatype="float" name="e_rmag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(erm) Error on rmag | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="imag" datatype="float" name="imag" precision="3" ucd="phot.mag;em.opt.I" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(aim) APASS i-band magnitude | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <FIELD ID="e_imag" datatype="float" name="e_imag" precision="3" ucd="stat.error;phot.mag" unit="mag" width="6"> | ||
| <DESCRIPTION> | ||
| ?(eim) Error on imag | ||
| </DESCRIPTION> | ||
| <VALUES null="nan"/> | ||
| </FIELD> | ||
| <DATA> | ||
| <TABLEDATA> | ||
| <TR> | ||
| <TD>0.049402</TD> | ||
| <TD>750-146023</TD> | ||
| <TD> 52.2340018</TD> | ||
| <TD> 59.8937333</TD> | ||
| <TD>9</TD> | ||
| <TD>6</TD> | ||
| <TD>13</TD> | ||
| <TD>13</TD> | ||
| <TD>2013.418</TD> | ||
| <TD>15.340</TD> | ||
| <TD> 0.013</TD> | ||
| <TD>13</TD> | ||
| <TD>9</TD> | ||
| <TD>74</TD> | ||
| <TD>74</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD> 1.5</TD> | ||
| <TD> -12.3</TD> | ||
| <TD> 5.9</TD> | ||
| <TD>1</TD> | ||
| <TD>5</TD> | ||
| <TD/> | ||
| <TD>758808681</TD> | ||
| <TD>13.713</TD> | ||
| <TD> 0.028</TD> | ||
| <TD>5</TD> | ||
| <TD>13.340</TD> | ||
| <TD> 0.034</TD> | ||
| <TD>5</TD> | ||
| <TD>13.101</TD> | ||
| <TD> 0.034</TD> | ||
| <TD>5</TD> | ||
| <TD>1</TD> | ||
| <TD>4</TD> | ||
| <TD>17.632</TD> | ||
| <TD> 0.204</TD> | ||
| <TD>16.164</TD> | ||
| <TD> 0.001</TD> | ||
| <TD>16.690</TD> | ||
| <TD> 0.001</TD> | ||
| <TD>15.750</TD> | ||
| <TD> 0.001</TD> | ||
| <TD/> | ||
| <TD/> | ||
| </TR> <TR> | ||
| <TD>0.049402</TD> | ||
| <TD>750-146023</TD> | ||
| <TD> 58.2340018</TD> | ||
| <TD> 69.8937333</TD> | ||
| <TD>9</TD> | ||
| <TD>6</TD> | ||
| <TD>13</TD> | ||
| <TD>13</TD> | ||
| <TD>2013.418</TD> | ||
| <TD>15.340</TD> | ||
| <TD> 0.013</TD> | ||
| <TD>13</TD> | ||
| <TD>9</TD> | ||
| <TD>74</TD> | ||
| <TD>74</TD> | ||
| <TD>0</TD> | ||
| <TD>0</TD> | ||
| <TD> 1.5</TD> | ||
| <TD> -12.3</TD> | ||
| <TD> 5.9</TD> | ||
| <TD>1</TD> | ||
| <TD>5</TD> | ||
| <TD/> | ||
| <TD>758808681</TD> | ||
| <TD>13.713</TD> | ||
| <TD> 0.028</TD> | ||
| <TD>5</TD> | ||
| <TD>13.340</TD> | ||
| <TD> 0.034</TD> | ||
| <TD>5</TD> | ||
| <TD>13.101</TD> | ||
| <TD> 0.034</TD> | ||
| <TD>5</TD> | ||
| <TD>1</TD> | ||
| <TD>4</TD> | ||
| <TD>17.632</TD> | ||
| <TD> 0.204</TD> | ||
| <TD>16.164</TD> | ||
| <TD> 0.001</TD> | ||
| <TD>16.690</TD> | ||
| <TD> 0.001</TD> | ||
| <TD>15.750</TD> | ||
| <TD> 0.001</TD> | ||
| <TD/> | ||
| <TD/> | ||
| </TR> | ||
| </TABLEDATA> | ||
| </DATA> | ||
| </TABLE> | ||
| </RESOURCE> | ||
| </VOTABLE> |
@@ -14,3 +14,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from . import XMLOutputChecker | ||
@@ -17,0 +17,0 @@ |
@@ -9,3 +9,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from pyvo.mivot.utils.mivot_utils import MivotUtils | ||
@@ -28,3 +28,3 @@ | ||
| m_viewer_votable_test = MivotViewer(votable_path=votable_test) | ||
| m_viewer_votable_test.next() | ||
| m_viewer_votable_test.next_row_view() | ||
| mivot_instance = m_viewer_votable_test.dm_instance | ||
@@ -91,3 +91,7 @@ xml_votable_test = m_viewer_votable_test.xml_view | ||
| assert value == MivotInstance_attribute.value | ||
| elif child.tag.startswith("REFERENCE"): | ||
| # Viewer not in resolve_ref mode: REFRENCEs are not filtered | ||
| pass | ||
| else: | ||
| print(child.tag) | ||
| assert False | ||
@@ -108,3 +112,3 @@ | ||
| m_viewer_votable_test = MivotViewer(votable_path=votable_test) | ||
| m_viewer_votable_test.next() | ||
| m_viewer_votable_test.next_row_view() | ||
| mivot_instance = m_viewer_votable_test.dm_instance | ||
@@ -111,0 +115,0 @@ _dict = MivotUtils.xml_to_dict(m_viewer_votable_test.xml_viewer.view) |
@@ -14,3 +14,3 @@ ''' | ||
| from pyvo.mivot.utils.mivot_utils import MivotUtils | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
@@ -36,2 +36,3 @@ fake_hk_dict = { | ||
| "longitude": { | ||
| "dmtype": "RealQuantity", | ||
| "value": 52.2340018, | ||
@@ -41,2 +42,3 @@ "unit": "deg", | ||
| "latitude": { | ||
| "dmtype": "RealQuantity", | ||
| "value": 59.8937333, | ||
@@ -56,3 +58,3 @@ "unit": "deg", | ||
| "dmtype": "cube:Observable", | ||
| "dependent": {"value": True}, | ||
| "dependent": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "measure": { | ||
@@ -64,3 +66,3 @@ "dmrole": "cube:MeasurementAxis.measure", | ||
| "dmtype": "coords:MJD", | ||
| "date": {"value": 1705.9437360200984}, | ||
| "date": {"dmtype": "ivoa:real", "value": 1705.9437360200984}, | ||
| }, | ||
@@ -71,3 +73,3 @@ }, | ||
| "dmtype": "cube:Observable", | ||
| "dependent": {"value": True}, | ||
| "dependent": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "measure": { | ||
@@ -79,3 +81,3 @@ "dmrole": "cube:MeasurementAxis.measure", | ||
| "dmtype": "coords:PhysicalCoordinate", | ||
| "cval": {"value": 15.216575}, | ||
| "cval": {"dmtype": "ivoa:RealQuantity", "value": 15.216575}, | ||
| }, | ||
@@ -86,3 +88,3 @@ }, | ||
| "dmtype": "cube:Observable", | ||
| "dependent": {"value": True}, | ||
| "dependent": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "measure": { | ||
@@ -94,3 +96,3 @@ "dmrole": "cube:MeasurementAxis.measure", | ||
| "dmtype": "coords:PhysicalCoordinate", | ||
| "cval": {"value": 15442.456}, | ||
| "cval": {"dmtype": "ivoa:RealQuantity", "value": 15442.456}, | ||
| }, | ||
@@ -103,3 +105,3 @@ "error": { | ||
| "dmtype": "meas:Symmetrical", | ||
| "radius": {"value": 44.15126}, | ||
| "radius": {"dmtype": "ivoa:RealQuantity", "value": 44.15126}, | ||
| }, | ||
@@ -106,0 +108,0 @@ }, |
@@ -13,3 +13,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from astropy import version as astropy_version | ||
@@ -16,0 +16,0 @@ |
@@ -42,3 +42,3 @@ ''' | ||
| }, | ||
| "epoch": { | ||
| "obsDate": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
@@ -49,11 +49,13 @@ "value": 1991.25, | ||
| }, | ||
| "coordSys": { | ||
| "spaceSys": { | ||
| "dmtype": "coords:SpaceSys", | ||
| "dmid": "SpaceFrame_ICRS", | ||
| "dmrole": "coords:Coordinate.coordSys", | ||
| "spaceRefFrame": { | ||
| "frame": { | ||
| "dmtype": "coords:SpaceFrame", | ||
| "value": "ICRS", | ||
| "unit": None, | ||
| "ref": None, | ||
| "dmrole": "coords:PhysicalCoordSys.frame", | ||
| "spaceRefFrame": { | ||
| "dmtype": "ivoa:string", | ||
| "value": "ICRS" | ||
| }, | ||
| }, | ||
@@ -95,3 +97,3 @@ }, | ||
| }, | ||
| "epoch": { | ||
| "obsDate": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
@@ -102,17 +104,19 @@ "value": 1991.25, | ||
| }, | ||
| "coordSys": { | ||
| "spaceSys": { | ||
| "dmtype": "coords:SpaceSys", | ||
| "dmid": "SpaceFrame_ICRS", | ||
| "dmrole": "coords:Coordinate.coordSys", | ||
| "spaceRefFrame": { | ||
| "dmtype": "coords:SpaceFrame.spaceRefFrame", | ||
| "value": "FK5", | ||
| "unit": None, | ||
| "ref": None, | ||
| }, | ||
| "equinox": { | ||
| "dmtype": "coords:SpaceFrame.equinox", | ||
| "value": "2012", | ||
| "unit": "yr", | ||
| }, | ||
| "frame": { | ||
| "dmtype": "coords:SpaceFrame", | ||
| "dmrole": "coords:PhysicalCoordSys.frame", | ||
| "spaceRefFrame": { | ||
| "dmtype": "ivoa:string", | ||
| "value": "FK5" | ||
| }, | ||
| "equinox": { | ||
| "dmtype": "coords:SpaceFrame.equinox", | ||
| "value": "2012", | ||
| "unit": "yr", | ||
| } | ||
| } | ||
| }, | ||
@@ -154,3 +158,3 @@ } | ||
| }, | ||
| "epoch": { | ||
| "obsDate": { | ||
| "dmtype": "ivoa:RealQuantity", | ||
@@ -205,3 +209,3 @@ "value": 1991.25, | ||
| vizier_dict["coordSys"]["spaceRefFrame"]["value"] = "Galactic" | ||
| vizier_dict["spaceSys"]["frame"]["spaceRefFrame"]["value"] = "Galactic" | ||
| mivot_instance = MivotInstance(**vizier_dict) | ||
@@ -213,3 +217,3 @@ scoo = mivot_instance.get_SkyCoord() | ||
| vizier_dict["coordSys"]["spaceRefFrame"]["value"] = "QWERTY" | ||
| vizier_dict["spaceSys"]["frame"]["spaceRefFrame"]["value"] = "QWERTY" | ||
| mivot_instance = MivotInstance(**vizier_dict) | ||
@@ -235,3 +239,3 @@ scoo = mivot_instance.get_SkyCoord() | ||
| vizier_equin_dict["coordSys"]["spaceRefFrame"]["value"] = "FK4" | ||
| vizier_equin_dict["spaceSys"]["frame"]["spaceRefFrame"]["value"] = "FK4" | ||
| mivot_instance = MivotInstance(**vizier_equin_dict) | ||
@@ -238,0 +242,0 @@ scoo = mivot_instance.get_SkyCoord() |
@@ -10,3 +10,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from . import XMLOutputChecker | ||
@@ -13,0 +13,0 @@ |
@@ -15,6 +15,6 @@ """ | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from astropy.io.votable import parse | ||
| from pyvo.mivot.utils.dict_utils import DictUtils | ||
| ref_ra = [ | ||
@@ -66,3 +66,3 @@ 0.04827189, | ||
| def vizier_url(): | ||
| return "https://cdsarc.cds.unistra.fr/beta/viz-bin/mivotconesearch/I/239/hip_main" | ||
| return "https://vizier.cds.unistra.fr/viz-bin/conesearch/V1.5/I/239/hip_main?RA=0&DEC=0&;SR=0.5" | ||
@@ -104,3 +104,3 @@ | ||
| """ | ||
| mivot_viewer = MivotViewer(path_to_votable) | ||
| mivot_viewer = MivotViewer(path_to_votable, resolve_ref=True) | ||
| mivot_instance = mivot_viewer.dm_instance | ||
@@ -113,3 +113,3 @@ assert mivot_instance.dmtype == "mango:EpochPosition" | ||
| pmdec = [] | ||
| while mivot_viewer.next(): | ||
| while mivot_viewer.next_row_view(): | ||
| ra.append(mivot_instance.longitude.value) | ||
@@ -137,3 +137,3 @@ dec.append(mivot_instance.latitude.value) | ||
| table = votable.resources[0].tables[0] | ||
| mivot_viewer = MivotViewer(votable) | ||
| mivot_viewer = MivotViewer(votable, resolve_ref=True) | ||
@@ -197,3 +197,3 @@ mivot_instance = mivot_viewer.dm_instance | ||
| mivot_object = mivot_viewer.dm_instance | ||
| while mivot_viewer.next(): | ||
| while mivot_viewer.next_row_view(): | ||
| read_ra.append(mivot_object.longitude.value) | ||
@@ -214,8 +214,7 @@ read_dec.append(mivot_object.latitude.value) | ||
| with MivotViewer(path_to_votable) as mivot_viewer: | ||
| with MivotViewer(path_to_votable, resolve_ref=True) as mivot_viewer: | ||
| mivot_object = mivot_viewer.dm_instance | ||
| # let's focus on the last data row | ||
| while mivot_viewer.next(): | ||
| # let"s focus on the last data row | ||
| while mivot_viewer.next_row_view(): | ||
| pass | ||
| DictUtils.print_pretty_json(mivot_object.to_hk_dict()) | ||
@@ -225,7 +224,7 @@ # check the slim (user friendly) dictionary | ||
| "dmtype": "mango:EpochPosition", | ||
| "longitude": {"value": 359.94372764, "unit": "deg"}, | ||
| "latitude": {"value": -0.28005255, "unit": "deg"}, | ||
| "pmLongitude": {"value": -5.14, "unit": "mas/yr"}, | ||
| "pmLatitude": {"value": -25.43, "unit": "mas/yr"}, | ||
| "epoch": {"value": 1991.25, "unit": "year"}, | ||
| "longitude": {"dmtype": "ivoa:RealQuantity", "value": 359.94372764, "unit": "deg"}, | ||
| "latitude": {"dmtype": "ivoa:RealQuantity", "value": -0.28005255, "unit": "deg"}, | ||
| "pmLongitude": {"dmtype": "ivoa:RealQuantity", "value": -5.14, "unit": "mas/yr"}, | ||
| "pmLatitude": {"dmtype": "ivoa:RealQuantity", "value": -25.43, "unit": "mas/yr"}, | ||
| "epoch": {"dmtype": "ivoa:RealQuantity", "value": 1991.25, "unit": "year"}, | ||
| "coordSys": { | ||
@@ -235,3 +234,3 @@ "dmtype": "coords:SpaceSys", | ||
| "dmrole": "coords:Coordinate.coordSys", | ||
| "spaceRefFrame": {"value": "ICRS"}, | ||
| "spaceRefFrame": {"dmtype": "coords:SpaceFrame", "value": "ICRS"}, | ||
| }, | ||
@@ -293,17 +292,17 @@ } | ||
| with MivotViewer(path_to_full_mapped_votable) as mivot_viewer: | ||
| with MivotViewer(path_to_full_mapped_votable, resolve_ref=True) as mivot_viewer: | ||
| mivot_object = mivot_viewer.dm_instance | ||
| # let's focus on the second data row | ||
| while mivot_viewer.next(): | ||
| # let"s focus on the second data row | ||
| while mivot_viewer.next_row_view(): | ||
| # check the slim (user friendly) dictionary | ||
| assert mivot_object.to_dict() == { | ||
| "dmtype": "mango:EpochPosition", | ||
| "longitude": {"value": 307.79115807079, "unit": "deg"}, | ||
| "latitude": {"value": 20.43108005561, "unit": "deg"}, | ||
| "parallax": {"value": 0.4319, "unit": "mas"}, | ||
| "radialVelocity": {"value": None, "unit": "km/s"}, | ||
| "pmLongitude": {"value": -2.557, "unit": "mas/yr"}, | ||
| "pmLatitude": {"value": -5.482, "unit": "mas/yr"}, | ||
| "epoch": {"value": "2016.5"}, | ||
| "pmCosDeltApplied": {"value": True}, | ||
| "longitude": {"dmtype": "ivoa:RealQuantity", "value": 307.79115807079, "unit": "deg"}, | ||
| "latitude": {"dmtype": "ivoa:RealQuantity", "value": 20.43108005561, "unit": "deg"}, | ||
| "parallax": {"dmtype": "ivoa:RealQuantity", "value": 0.4319, "unit": "mas"}, | ||
| "radialVelocity": {"dmtype": "ivoa:RealQuantity", "value": None, "unit": "km/s"}, | ||
| "pmLongitude": {"dmtype": "ivoa:RealQuantity", "value": -2.557, "unit": "mas/yr"}, | ||
| "pmLatitude": {"dmtype": "ivoa:RealQuantity", "value": -5.482, "unit": "mas/yr"}, | ||
| "epoch": {"dmtype": "coords:Epoch", "value": "2016.5"}, | ||
| "pmCosDeltApplied": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "errors": { | ||
@@ -315,3 +314,3 @@ "dmrole": "mango:EpochPosition.errors", | ||
| "dmtype": "mango:ErrorTypes.PropertyError1D", | ||
| "sigma": {"value": 0.06909999996423721, "unit": "mas"}, | ||
| "sigma": {"dmtype": "ivoa:real", "value": 0.06909999996423721, "unit": "mas"}, | ||
| }, | ||
@@ -321,3 +320,3 @@ "radialVelocity": { | ||
| "dmtype": "mango:ErrorTypes.PropertyError1D", | ||
| "sigma": {"value": None, "unit": "km/s"}, | ||
| "sigma": {"dmtype": "ivoa:real", "value": None, "unit": "km/s"}, | ||
| }, | ||
@@ -327,4 +326,4 @@ "position": { | ||
| "dmtype": "mango:ErrorTypes.ErrorMatrix", | ||
| "sigma1": {"value": 0.0511, "unit": "mas"}, | ||
| "sigma2": {"value": 0.0477, "unit": "mas"}, | ||
| "sigma1": {"dmtype": "ivoa:real", "value": 0.0511, "unit": "mas"}, | ||
| "sigma2": {"dmtype": "ivoa:real", "value": 0.0477, "unit": "mas"}, | ||
| }, | ||
@@ -334,4 +333,4 @@ "properMotion": { | ||
| "dmtype": "mango:ErrorTypes.ErrorMatrix", | ||
| "sigma1": {"value": 0.06400000303983688, "unit": "mas/yr"}, | ||
| "sigma2": {"value": 0.06700000166893005, "unit": "mas/yr"}, | ||
| "sigma1": {"dmtype": "ivoa:real", "value": 0.06400000303983688, "unit": "mas/yr"}, | ||
| "sigma2": {"dmtype": "ivoa:real", "value": 0.06700000166893005, "unit": "mas/yr"}, | ||
| }, | ||
@@ -345,7 +344,7 @@ }, | ||
| "dmtype": "mango:Correlation22", | ||
| "isCovariance": {"value": True}, | ||
| "a2b1": {"value": -0.0085}, | ||
| "a2b2": {"value": -0.2983}, | ||
| "a1b1": {"value": -0.4109}, | ||
| "a1b2": {"value": -0.0072}, | ||
| "isCovariance": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "a2b1": {"dmtype": "ivoa:real", "value": -0.0085}, | ||
| "a2b2": {"dmtype": "ivoa:real", "value": -0.2983}, | ||
| "a1b1": {"dmtype": "ivoa:real", "value": -0.4109}, | ||
| "a1b2": {"dmtype": "ivoa:real", "value": -0.0072}, | ||
| }, | ||
@@ -355,5 +354,5 @@ "parallaxPm": { | ||
| "dmtype": "mango:Correlation12", | ||
| "isCovariance": {"value": True}, | ||
| "a1b1": {"value": -0.2603}, | ||
| "a1b2": {"value": -0.0251}, | ||
| "isCovariance": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "a1b1": {"dmtype": "ivoa:real", "value": -0.2603}, | ||
| "a1b2": {"dmtype": "ivoa:real", "value": -0.0251}, | ||
| }, | ||
@@ -363,5 +362,5 @@ "positionParallax": { | ||
| "dmtype": "mango:Correlation21", | ||
| "isCovariance": {"value": True}, | ||
| "a2b1": {"value": 0.0069}, | ||
| "a1b1": {"value": 0.1337}, | ||
| "isCovariance": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "a2b1": {"dmtype": "ivoa:real", "value": 0.0069}, | ||
| "a1b1": {"dmtype": "ivoa:real", "value": 0.1337}, | ||
| }, | ||
@@ -371,5 +370,5 @@ "positionPosition": { | ||
| "dmtype": "mango:Correlation22", | ||
| "isCovariance": {"value": True}, | ||
| "a2b1": {"value": 0.1212}, | ||
| "a1b2": {"value": 0.1212}, | ||
| "isCovariance": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "a2b1": {"dmtype": "ivoa:real", "value": 0.1212}, | ||
| "a1b2": {"dmtype": "ivoa:real", "value": 0.1212}, | ||
| }, | ||
@@ -379,5 +378,5 @@ "properMotionPm": { | ||
| "dmtype": "mango:Correlation22", | ||
| "isCovariance": {"value": True}, | ||
| "a2b1": {"value": 0.2688}, | ||
| "a1b2": {"value": 0.2688}, | ||
| "isCovariance": {"dmtype": "ivoa:boolean", "value": True}, | ||
| "a2b1": {"dmtype": "ivoa:real", "value": 0.2688}, | ||
| "a1b2": {"dmtype": "ivoa:real", "value": 0.2688}, | ||
| }, | ||
@@ -392,3 +391,3 @@ }, | ||
| "dmtype": "coords:SpaceFrame", | ||
| "spaceRefFrame": {"value": "ICRS"}, | ||
| "spaceRefFrame": {"dmtype": "ivoa:string", "value": "ICRS"}, | ||
| }, | ||
@@ -411,7 +410,8 @@ }, | ||
| radius=0.05, | ||
| ) | ||
| ), | ||
| resolve_ref=True | ||
| ) | ||
| mivot_instance = m_viewer.dm_instance | ||
| assert mivot_instance.dmtype == "mango:EpochPosition" | ||
| assert mivot_instance.coordSys.spaceRefFrame.value == "ICRS" | ||
| assert mivot_instance.spaceSys.frame.spaceRefFrame.value == "ICRS" | ||
| ra = [] | ||
@@ -421,3 +421,4 @@ dec = [] | ||
| pmdec = [] | ||
| while m_viewer.next(): | ||
| while m_viewer.next_row_view(): | ||
| ra.append(mivot_instance.longitude.value) | ||
@@ -424,0 +425,0 @@ dec.append(mivot_instance.latitude.value) |
@@ -23,3 +23,3 @@ ''' | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from pyvo.mivot.utils.exceptions import MivotError | ||
@@ -86,4 +86,4 @@ | ||
| """ | ||
| m_viewer = MivotViewer(votable_path=path_to_withname) | ||
| m_viewer.next() | ||
| m_viewer = MivotViewer(votable_path=path_to_withname, resolve_ref=True) | ||
| m_viewer.next_row_view() | ||
| mivot_object = m_viewer.dm_instance | ||
@@ -98,3 +98,3 @@ | ||
| m_viewer.next() | ||
| m_viewer.next_row_view() | ||
@@ -116,3 +116,3 @@ assert abs(mivot_object.longitude.value - 32.2340018) < delt_coo | ||
| m_viewer = MivotViewer(votable_path=path_to_withid) | ||
| m_viewer.next() | ||
| m_viewer.next_row_view() | ||
| mivot_instance = m_viewer.dm_instance | ||
@@ -119,0 +119,0 @@ assert abs(mivot_instance.longitude.value - 52.2340018) < delt_coo |
@@ -12,3 +12,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| from pyvo.mivot.version_checker import check_astropy_version | ||
| from pyvo.mivot import MivotViewer | ||
| from pyvo.mivot.viewer import MivotViewer | ||
| from pyvo.mivot.utils.exceptions import MivotError | ||
@@ -20,3 +20,3 @@ | ||
| m_viewer.next() | ||
| m_viewer.next_row_view() | ||
| xml_viewer = m_viewer.xml_viewer | ||
@@ -23,0 +23,0 @@ with pytest.raises(MivotError, |
@@ -16,2 +16,24 @@ """ | ||
| @staticmethod | ||
| def add_array_element(dictionnary, key): | ||
| """ | ||
| Add a [] as key element if not exist | ||
| Parameters: | ||
| ----------- | ||
| dictionnary: dict | ||
| dictionnary to be updated | ||
| key: string | ||
| key to be added | ||
| Returns: | ||
| -------- | ||
| Bool | ||
| True if the key element has been added | ||
| """ | ||
| if key not in dictionnary: | ||
| dictionnary[key] = [] | ||
| return True | ||
| return False | ||
| @staticmethod | ||
| def read_dict_from_file(filename, fatal=False): | ||
@@ -31,9 +53,9 @@ """ | ||
| from collections import OrderedDict | ||
| with open(filename, 'r') as file: | ||
| with open(filename) as file: | ||
| return json.load(file, object_pairs_hook=OrderedDict) | ||
| except Exception as exception: | ||
| if fatal: | ||
| raise MivotError("reading {}".format(filename)) | ||
| raise MivotError(f"reading {filename}") | ||
| else: | ||
| logging.error("{} reading {}".format(exception, filename)) | ||
| logging.error(f"{exception} reading {filename}") | ||
@@ -40,0 +62,0 @@ @staticmethod |
@@ -30,2 +30,2 @@ import json | ||
| else: | ||
| return super(MivotJsonEncoder, self).default(obj) | ||
| return super().default(obj) |
| ''' | ||
| Some utilities making easier the transformation of Mivot elements into dictionary components. | ||
| These dictionaries are used to generate ``MivotInstance`` objects | ||
| Utilities handling various operations on Mivot instances | ||
| ''' | ||
| import numpy | ||
| from pyvo.mivot.utils.exceptions import MappingError | ||
| from pyvo.mivot.glossary import IvoaType, Roles, ModelPrefix | ||
| class MivotUtils(object): | ||
| class MivotUtils: | ||
| """ | ||
| Some utilities making easier the transformation of Mivot elements into dictionary components. | ||
| These dictionaries are used to generate ``MivotInstance`` objects | ||
| """ | ||
| @staticmethod | ||
| def _valid_mapped_dmroles(mapped_roles, class_name): | ||
| """ | ||
| Check that the given mapped roles of the given class, are in the `pyvo.mivot.glossary.Roles`, | ||
| which reflects the model. | ||
| Parameters | ||
| ---------- | ||
| mapped_roles: dict | ||
| Dictionary of the matches between the dmroles (dict keys) and | ||
| the column identifiers (dict values). This mapping is a user input. | ||
| class_name: str | ||
| Name of the class to which the mapping applies | ||
| Returns | ||
| ------- | ||
| dict | ||
| The dictionary of valid matches between the dmroles (dict keys) and | ||
| the column identifiers (dict values). | ||
| Raises | ||
| ------ | ||
| MappingError | ||
| If the class ``class_name`` is not supported or if | ||
| some mapped role does not exist for the glossary | ||
| """ | ||
| # Check that the class is in the glossary | ||
| if not hasattr(Roles, class_name): | ||
| raise MappingError(f"Unknown or unimplemented class {class_name}") | ||
| # get the list of supported roles | ||
| dmroles = getattr(Roles, class_name) | ||
| real_mapping = [] | ||
| for mapped_role, column in mapped_roles: | ||
| # 'class' is a reserved word, not a role | ||
| if mapped_role == "class" or isinstance(column, dict) or isinstance(column, list): | ||
| continue | ||
| found = False | ||
| for leaf in dmroles: | ||
| dmrole = f"{ModelPrefix.mango}:{class_name}.{leaf}" | ||
| if dmrole.lower().endswith("." + mapped_role.lower()): | ||
| real_mapping.append((dmrole, column)) | ||
| found = True | ||
| break | ||
| if not found: | ||
| raise MappingError(f"Class {ModelPrefix.mango}:{class_name} " | ||
| f"has no {mapped_role} attribute." | ||
| f"Supported roles are {dmroles}") | ||
| return real_mapping | ||
| @staticmethod | ||
| def xml_to_dict(element): | ||
| """ | ||
| Recursively create a nested dictionary from the XML tree structure, preserving the hierarchy. | ||
| Each object in the dictionary is represented by a new dictionary with dmrole: {}. | ||
| Recursively create a nested dictionary from the XML tree structure, | ||
| preserving the hierarchy. | ||
| The processing of elements depends on the tag: | ||
| - For INSTANCE, a new dictionary is created. | ||
| - For COLLECTION, a list is created. | ||
| - For ATTRIBUTE, a leaf is created in the tree structure with dmtype, dmrole, value, unit, and ref. | ||
| - For ATTRIBUTE, a leaf structure is created in the tree structure with dmtype, | ||
| dmrole, value, unit, and ref keys. | ||
| Parameters | ||
| ---------- | ||
| element (~`xml.etree.ElementTree.Element`) : The XML element to convert to a dictionary. | ||
| element : `xml.etree.ElementTree.Element` | ||
| The XML element to convert to a dictionary | ||
| Returns | ||
| ------- | ||
| dict: The nested dictionary representing the XML tree structure. | ||
| dict | ||
| The nested dictionary representing the XML tree structure. | ||
| """ | ||
@@ -31,50 +94,57 @@ dict_result = {} | ||
| if child.tag == "ATTRIBUTE": | ||
| dict_result[dmrole] = MivotUtils.attribute_to_dict(child) | ||
| dict_result[dmrole] = MivotUtils._attribute_to_dict(child) | ||
| elif child.tag == "INSTANCE": # INSTANCE is recursively well managed by the function _to_dict | ||
| dict_result[dmrole] = MivotUtils.xml_to_dict(child) | ||
| elif child.tag == "COLLECTION": | ||
| dict_result[dmrole] = MivotUtils.collection_to_dict(child) | ||
| dict_result[dmrole] = MivotUtils._collection_to_dict(child) | ||
| return dict_result | ||
| @staticmethod | ||
| def attribute_to_dict(child): | ||
| def _attribute_to_dict(child): | ||
| """ | ||
| Convert an ATTRIBUTE element to a dictionary. | ||
| ATTRIBUTE is always a leaf, so it is not recursive. | ||
| Convert an ATTRIBUTE (XML) element to a dictionary. | ||
| ATTRIBUTE being always a leaf, the conversion is not recursive. | ||
| Parameters | ||
| ---------- | ||
| child (~`xml.etree.ElementTree.Element`): ATTRIBUTE XML element to convert. | ||
| child : `xml.etree.ElementTree.Element` | ||
| ATTRIBUTE XML element to convert. | ||
| Returns | ||
| ------- | ||
| dict: A dictionary representing the ATTRIBUTE element with keys: | ||
| 'dmtype', 'dmrole', 'value', 'unit', and 'ref'. | ||
| dict: | ||
| A dictionary representing the ATTRIBUTE element with keys: | ||
| 'dmtype', 'dmrole', 'value', 'unit', and 'ref'. | ||
| """ | ||
| attribute = {} | ||
| if child.get('dmtype') is not None: | ||
| attribute['dmtype'] = child.get("dmtype") | ||
| if child.get("dmtype") is not None: | ||
| attribute["dmtype"] = child.get("dmtype") | ||
| if child.get("value") is not None: | ||
| attribute['value'] = MivotUtils.cast_type_value(child.get("value"), child.get("dmtype")) | ||
| attribute["value"] = MivotUtils.cast_type_value(child.get("value"), child.get("dmtype")) | ||
| else: | ||
| attribute['value'] = None | ||
| attribute["value"] = None | ||
| if child.get("unit") is not None: | ||
| attribute['unit'] = child.get("unit") | ||
| attribute["unit"] = child.get("unit") | ||
| else: | ||
| attribute['unit'] = None | ||
| attribute["unit"] = None | ||
| if child.get("ref") is not None: | ||
| attribute['ref'] = child.get("ref") | ||
| attribute["ref"] = child.get("ref") | ||
| else: | ||
| attribute['ref'] = None | ||
| attribute["ref"] = None | ||
| return attribute | ||
| @staticmethod | ||
| def collection_to_dict(child): | ||
| def _collection_to_dict(child): | ||
| """ | ||
| Convert a COLLECTION element to a list of dictionaries. | ||
| COLLECTION is always represented as a list, and each element of the COLLECTION is added to the list. | ||
| Convert a COLLECTION element (child) to a list of dictionaries. | ||
| Parameters | ||
| ---------- | ||
| child (`~`xml.etree.ElementTree.Element``): COLLECTION XML element to convert. | ||
| child : `xml.etree.ElementTree.Element` | ||
| COLLECTION XML element to convert | ||
| Returns | ||
| ------- | ||
| list: list of dictionaries representing the elements of the COLLECTION. | ||
| list({}) | ||
| list of dictionaries representing the COLLECTION items | ||
| """ | ||
@@ -89,17 +159,22 @@ collection_items = [] | ||
| """ | ||
| Cast the value of an ATTRIBUTE based on its dmtype. | ||
| As the type of ATTRIBUTE values returned in the dictionary is string by default, | ||
| this function is used to cast them based on their dmtype. | ||
| Cast value to the Python type matching dmtype. | ||
| Parameters | ||
| ---------- | ||
| value (str): value of the ATTRIBUTE. | ||
| dmtype (str): dmtype of the ATTRIBUTE. | ||
| value : str | ||
| value to cast | ||
| dmtype : str | ||
| model dmtype | ||
| Returns | ||
| ------- | ||
| Union[bool, float, str, None] | ||
| The cast value based on the dmtype. | ||
| The casted value or None | ||
| """ | ||
| if type(value) is numpy.float32 or type(value) is numpy.float64: | ||
| lower_dmtype = dmtype.lower() | ||
| # empty strings cannot be casted | ||
| if "string" not in lower_dmtype and value == "": | ||
| return None | ||
| if numpy.issubdtype(type(value), numpy.floating): | ||
| return float(value) | ||
| lower_dmtype = dmtype.lower() | ||
| if isinstance(value, str): | ||
@@ -123,1 +198,125 @@ lower_value = value.lower() | ||
| return value | ||
| @staticmethod | ||
| def format_dmid(dmid): | ||
| """ | ||
| Replace characters that could confuse XPath queries with '_'. | ||
| This is not required by the MIVOT schema but this makes this API more robust | ||
| Returns | ||
| ------- | ||
| str | ||
| formatted dmid | ||
| """ | ||
| if dmid is not None: | ||
| return dmid.replace("/", "_").replace(".", "_").replace("-", "_") | ||
| return "" | ||
| @staticmethod | ||
| def get_field_attributes(table, column_id): | ||
| """ | ||
| Parameters | ||
| ---------- | ||
| table : astropy.table | ||
| Table (from parsed VOTable) of the mapped data | ||
| column_id : str | ||
| Identifier of the table column from which we want to get the unit | ||
| Returns | ||
| ------- | ||
| unit, ref, literal | ||
| """ | ||
| ref, literal = MivotUtils.get_ref_or_literal(column_id) | ||
| if literal: | ||
| return None, None, literal | ||
| else: | ||
| try: | ||
| field = table.get_field_by_id_or_name(ref) | ||
| return str(field.unit), column_id, None | ||
| except KeyError as keyerror: | ||
| raise MappingError(f"Cannot find any field identified by {column_id}") from keyerror | ||
| @staticmethod | ||
| def get_ref_or_literal(value_or_ref): | ||
| """ | ||
| Check if value_or_ref must be interpreted as a column reference or a literal. | ||
| Returns | ||
| ------- | ||
| (ref, literal) | ||
| """ | ||
| if not value_or_ref: | ||
| raise MappingError("An attribute cannot be set with a None value") | ||
| elif isinstance(value_or_ref, str): | ||
| return ((None, value_or_ref.replace("*", "")) if value_or_ref.startswith("*") | ||
| else (value_or_ref, None)) | ||
| else: | ||
| return (None, value_or_ref) | ||
| @staticmethod | ||
| def as_literal(identifier): | ||
| """ | ||
| Make sure the identifier will be interpreted as a literal (* prefix). | ||
| Literal are either non string values or strings starting with a * | ||
| Parameters | ||
| ---------- | ||
| identifier: str | ||
| column identifier or literal value | ||
| Returns | ||
| ------- | ||
| str | ||
| identifier prefixes with a * | ||
| """ | ||
| if isinstance(identifier, str) and not identifier.startswith("*"): | ||
| return "*" + identifier | ||
| return identifier | ||
| @staticmethod | ||
| def populate_instance(property_instance, class_name, | ||
| mapping, table, dmtype, as_literals=False, package=None): | ||
| """ | ||
| This function inserts in the property_instance all expected attributes. | ||
| - The structure of the class is supposed to be flat (only ATTRIBUTEs). | ||
| - All attributes are meant to have the same dmtype. | ||
| - The mapping is checked against the `pyvo.mivot.glossary.Roles`. | ||
| Parameters | ||
| ---------- | ||
| property_instance : `pyvo.mivot.writer.instance.MivotInstance` | ||
| Mivot instance to populate with attributes | ||
| class_name : str | ||
| Name of the property_instance class (dmtype). | ||
| Used to get all the attribute roles (given by the model) of the class | ||
| mapping : dict | ||
| Dictionary associating model roles with their values. | ||
| table : astropy.table | ||
| Table (from parsed VOTable) of the mapped data | ||
| dmtype : string | ||
| common dmtype of object attributes | ||
| as_literal : boolean, optional (default isTrue) | ||
| If True, all attribute are set with literal values (@value="...") | ||
| package : str, optional (default as None) | ||
| Package name possibly prefixing dmroles | ||
| """ | ||
| mapped_roles = MivotUtils._valid_mapped_dmroles(mapping.items(), class_name) | ||
| pkg = f"{package}." if package else "" | ||
| for dmrole, column in mapped_roles: | ||
| # minimal reserved characters escaping | ||
| if isinstance(column, str): | ||
| column = column.replace("&", "&") | ||
| # force column references to be processed as literals if requested | ||
| if as_literals: | ||
| column = MivotUtils.as_literal(column) | ||
| unit, _, _ = MivotUtils.get_field_attributes(table, column) | ||
| if isinstance(column, bool): | ||
| r_dmtype = IvoaType.bool | ||
| else: | ||
| r_dmtype = dmtype | ||
| r_dmrole = dmrole.replace(":", f":{pkg}") | ||
| property_instance.add_attribute(dmtype=r_dmtype, | ||
| dmrole=r_dmrole, | ||
| value=column, | ||
| unit=unit) |
| """ | ||
| Utility class to process XML. | ||
| """ | ||
| import re | ||
| from pyvo.mivot.utils.xpath_utils import XPath | ||
| import xml.etree.ElementTree as ET | ||
| from xml.dom import minidom | ||
| from pyvo.mivot.utils.vocabulary import Constant | ||
@@ -16,18 +18,34 @@ from pyvo.mivot.utils.vocabulary import Att | ||
| @staticmethod | ||
| def pretty_print(xmltree): | ||
| def pretty_print(xmltree, *, lshift=""): | ||
| """ | ||
| Pretty print an XML tree. | ||
| Pretty print an XML tree | ||
| Parameters | ||
| ---------- | ||
| xmltree (~`xml.etree.ElementTree.Element`): XML tree to pretty print. | ||
| xmltree: (~`xml.etree.ElementTree.Element`) | ||
| XML tree to pretty print | ||
| lshift : str, optional, default "" | ||
| Sequence to be inserted at the beginning of each line | ||
| Usually a space sequence | ||
| """ | ||
| print(XmlUtils.pretty_string(xmltree)) | ||
| print(XmlUtils.pretty_string(xmltree, lshift=lshift)) | ||
| @staticmethod | ||
| def pretty_string(xmltree): | ||
| def pretty_string(xmltree, *, lshift="", clean_namespace=True): | ||
| """ | ||
| Return a pretty string representation of an XML tree. | ||
| Return a pretty string representation of an XML tree (as Etree or string) | ||
| Parameters | ||
| ---------- | ||
| xmltree (~`xml.etree.ElementTree.Element`): XML tree to convert to a pretty string. | ||
| xmltree (~`xml.etree.ElementTree.Element`) or string: | ||
| XML tree to convert to a pretty string | ||
| lshift : str, optional, default "" | ||
| Sequence to be inserted at the beginning of each line | ||
| Usually a space sequence | ||
| clean_namespace : boolean, optional, default True | ||
| Default namespace (ns0) removed from element names if True | ||
| Returns | ||
@@ -37,38 +55,36 @@ ------- | ||
| """ | ||
| if hasattr(xmltree, 'getroot'): | ||
| XmlUtils.indent(xmltree.getroot()) | ||
| new_xml = ET.tostring(xmltree.getroot(), encoding='unicode') | ||
| if isinstance(xmltree, str): | ||
| root = xmltree | ||
| else: | ||
| XmlUtils.indent(xmltree) | ||
| new_xml = ET.tostring(xmltree, encoding='unicode') | ||
| return new_xml.replace("ns0:", "") | ||
| if hasattr(xmltree, 'getroot'): | ||
| root = ET.tostring(xmltree.getroot(), encoding='unicode') | ||
| else: | ||
| root = ET.tostring(xmltree, encoding='unicode') | ||
| root = root.replace("<?xml version=\"1.0\" ?>\n", "") | ||
| reparsed = minidom.parseString(root) | ||
| pretty_string = re.sub(r" +\n", "", reparsed.toprettyxml(indent=" ")) | ||
| pretty_string = pretty_string.replace("<?xml version=\"1.0\" ?>\n", "") \ | ||
| .replace("\n\n", "\n") \ | ||
| .replace("<", f"{lshift}<") | ||
| if clean_namespace: | ||
| return pretty_string.replace("ns0:", "") | ||
| else: | ||
| return pretty_string | ||
| @staticmethod | ||
| def indent(elem, level=0): | ||
| def strip_xml(xml_string): | ||
| """ | ||
| Indent an XML tree. | ||
| Parameters | ||
| ---------- | ||
| elem (~`xml.etree.ElementTree.Element`): XML tree to indent. | ||
| level (int): level of indentation. | ||
| Returns | ||
| ------- | ||
| ~`xml.etree.ElementTree.Element` | ||
| The indented XML tree. | ||
| Strip unnecessary whitespace and newline characters from an XML string. | ||
| Used by unit tests to compare xml strings | ||
| Parameters: | ||
| - xml_string (str): The XML string to strip. | ||
| Returns: | ||
| - str: The stripped XML string. | ||
| """ | ||
| i = "\n" + level * " " | ||
| j = "\n" + (level - 1) * " " | ||
| if len(elem): | ||
| if not elem.text or not elem.text.strip(): | ||
| elem.text = i + " " | ||
| if not elem.tail or not elem.tail.strip(): | ||
| elem.tail = i | ||
| for subelem in elem: | ||
| XmlUtils.indent(subelem, level + 1) | ||
| if not elem.tail or not elem.tail.strip(): | ||
| elem.tail = j | ||
| else: | ||
| if level and (not elem.tail or not elem.tail.strip()): | ||
| elem.tail = j | ||
| return elem | ||
| return ( | ||
| xml_string.replace("\n", "").replace(" ", "").replace("'", "").replace('"', "") | ||
| ) | ||
@@ -75,0 +91,0 @@ @staticmethod |
@@ -75,12 +75,3 @@ """ | ||
| """ | ||
| cnt = 1 | ||
| result = [] | ||
| run = True | ||
| while run: | ||
| if etree.find(path + str(cnt)) is not None: | ||
| result.append(etree.find(path + str(cnt))) | ||
| cnt += 1 | ||
| else: | ||
| run = False | ||
| return result | ||
| return {elem for elem in etree.iter() if elem.tag.startswith("REFERENCE_")} | ||
@@ -87,0 +78,0 @@ @staticmethod |
@@ -121,3 +121,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| value.update(row=row) | ||
| if 'value' in vars(value): | ||
| if 'ref' in vars(value): | ||
| value.update(row=row, ref=getattr(value, 'ref')) | ||
@@ -169,3 +169,3 @@ else: | ||
| def _get_class_dict(self, obj, classkey=None, slim=False): | ||
| def _get_class_dict(self, obj, classkey=None, slim=False, with_dmtypes=True): | ||
| """ | ||
@@ -183,2 +183,4 @@ Recursively displays a serializable dictionary. | ||
| @dmtype and @ref attributes are ignored | ||
| with_dmtypes (boolean, optional) : if true dmtypes are added to the | ||
| primitive types (model leaves) | ||
| Returns | ||
@@ -200,9 +202,9 @@ ------- | ||
| elif hasattr(obj, "__dict__"): | ||
| data = dict([(key, obj._get_class_dict(value, classkey, slim=slim)) | ||
| data = {key: obj._get_class_dict(value, classkey, slim=slim) | ||
| for key, value in obj.__dict__.items() | ||
| if not callable(value) and not key.startswith('_')]) | ||
| if not callable(value) and not key.startswith('_')} | ||
| # remove the house keeping parameters | ||
| if slim is True: | ||
| # data is atomic value (e.g. float): the type be hidden | ||
| if "ref" in data or "value" in data: | ||
| if with_dmtypes is False and ("ref" in data or "value" in data): | ||
| data.pop("dmtype", None) | ||
@@ -209,0 +211,0 @@ # remove unit when not set |
@@ -18,3 +18,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| mivot_object = mivot_viewer.dm_instance | ||
| while mivot_viewer.next(): | ||
| while mivot_viewer.next_row_view(): | ||
| print(f"latitude={mivot_object.latitude.value}") | ||
@@ -60,3 +60,3 @@ print(f"longitude={mivot_object.longitude.value}") | ||
| """ | ||
| def __init__(self, votable_path, tableref=None): | ||
| def __init__(self, votable_path, tableref=None, resolve_ref=False): | ||
| """ | ||
@@ -73,2 +73,9 @@ Constructor of the MivotViewer class. | ||
| the first table is taken by default. | ||
| Parameters | ||
| ---------- | ||
| resolve_ref : bool, optional | ||
| If True, replace the REFERENCE elements with a copy of the objects they refer to. | ||
| e.g. copy the space coordinates system, usually located in the GLOBALS | ||
| block, in the position objects | ||
| Default is False. | ||
| """ | ||
@@ -99,2 +106,3 @@ if not check_astropy_version(): | ||
| self._dm_instance = None | ||
| self._resolve_ref = resolve_ref | ||
| try: | ||
@@ -195,3 +203,3 @@ self._set_resource() | ||
| def next(self): | ||
| def next_row_view(self): | ||
| """ | ||
@@ -379,14 +387,9 @@ jump to the next table row and update the MivotInstance instance | ||
| def _get_model_view(self, resolve_ref=True): | ||
| def _get_model_view(self): | ||
| """ | ||
| Return an XML model view of the last read row. | ||
| This function resolves references by default. | ||
| Parameters | ||
| ---------- | ||
| resolve_ref : bool, optional | ||
| If True, resolves the references. Default is True. | ||
| """ | ||
| templates_copy = deepcopy(self._templates) | ||
| if resolve_ref is True: | ||
| if self._resolve_ref is True: | ||
| while StaticReferenceResolver.resolve(self._annotation_seeker, self._connected_tableref, | ||
@@ -393,0 +396,0 @@ templates_copy) > 0: |
@@ -15,3 +15,4 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| Freetext, Author, Servicetype, Waveband, Datamodel, Ivoid, | ||
| UCD, Spatial, Spectral, Temporal, RegTAPFeatureMissing) | ||
| UCD, UAT, Spatial, Spectral, Temporal, | ||
| RegTAPFeatureMissing) | ||
@@ -21,4 +22,4 @@ __all__ = ["search", "get_RegTAP_query", "Constraint", "SubqueriedConstraint", | ||
| "Servicetype", "Waveband", "Datamodel", "Ivoid", "UCD", | ||
| "Spatial", "Spectral", "Temporal", | ||
| "UAT", "Spatial", "Spectral", "Temporal", | ||
| "choose_RegTAP_service", "RegTAPFeatureMissing", | ||
| "RegistryResults", "RegistryResource",] |
@@ -321,11 +321,11 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| @functools.lru_cache(maxsize=None) | ||
| @functools.cache | ||
| def _get_ivo_index(self): | ||
| return dict((r.ivoid, index) | ||
| for index, r in enumerate(self)) | ||
| return {r.ivoid: index | ||
| for index, r in enumerate(self)} | ||
| @functools.lru_cache(maxsize=None) | ||
| @functools.cache | ||
| def _get_short_name_index(self): | ||
| return dict((r.short_name, index) | ||
| for index, r in enumerate(self)) | ||
| return {r.short_name: index | ||
| for index, r in enumerate(self)} | ||
@@ -732,6 +732,6 @@ def __getitem__(self, item): | ||
| """ | ||
| return set(shorten_stdid(intf.standard_id) or "web" | ||
| return {shorten_stdid(intf.standard_id) or "web" | ||
| for intf in self.interfaces | ||
| if (intf.standard_id or intf.type == "vr:webbrowser") | ||
| and not intf.is_vosi) | ||
| and not intf.is_vosi} | ||
@@ -738,0 +738,0 @@ def get_interface(self, *, |
+116
-26
@@ -35,19 +35,19 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| # from regtap. | ||
| SERVICE_TYPE_MAP = dict((k, "ivo://ivoa.net/std/" + v) | ||
| SERVICE_TYPE_MAP = {k: "ivo://ivoa.net/std/" + v | ||
| for k, v in [ | ||
| ("image", "sia"), | ||
| ("sia", "sia"), | ||
| ("sia1", "sia"), | ||
| # SIA2 is irregular | ||
| # funky scheme used by SIA2 without breaking everything else | ||
| ("spectrum", "ssa"), | ||
| ("ssap", "ssa"), | ||
| ("ssa", "ssa"), | ||
| ("scs", "conesearch"), | ||
| ("conesearch", "conesearch"), | ||
| ("line", "slap"), | ||
| ("slap", "slap"), | ||
| ("table", "tap"), | ||
| ("tap", "tap"), | ||
| ]) | ||
| ("image", "sia"), | ||
| ("sia", "sia"), | ||
| ("sia1", "sia"), | ||
| # SIA2 is irregular | ||
| # funky scheme used by SIA2 without breaking everything else | ||
| ("spectrum", "ssa"), | ||
| ("ssap", "ssa"), | ||
| ("ssa", "ssa"), | ||
| ("scs", "conesearch"), | ||
| ("conesearch", "conesearch"), | ||
| ("line", "slap"), | ||
| ("slap", "slap"), | ||
| ("table", "tap"), | ||
| ("tap", "tap"), | ||
| ]} | ||
@@ -110,4 +110,7 @@ | ||
| elif isinstance(value, datetime.datetime): | ||
| return "'{}'".format(value.isoformat()) | ||
| return f"'{value.isoformat()}'" | ||
| elif isinstance(value, set): | ||
| return '('+", ".join(make_sql_literal(s) for s in sorted(value))+')' | ||
| else: | ||
@@ -294,4 +297,4 @@ raise ValueError("Cannot format {} as a SQL literal" | ||
| for index, word in enumerate(self.words): | ||
| parname = "fulltext{}".format(index) | ||
| parpatname = "fulltextpar{}".format(index) | ||
| parname = f"fulltext{index}" | ||
| parpatname = f"fulltextpar{index}" | ||
| self._fillers[parname] = word | ||
@@ -316,4 +319,4 @@ self._fillers[parpatname] = '%' + word + '%' | ||
| for index, word in enumerate(self.words): | ||
| parname = "fulltext{}".format(index) | ||
| parpatname = "fulltextpar{}".format(index) | ||
| parname = f"fulltext{index}" | ||
| parpatname = f"fulltextpar{index}" | ||
| self._fillers[parname] = word | ||
@@ -463,4 +466,4 @@ self._fillers[parpatname] = '%' + word + '%' | ||
| expanded = self.clone() | ||
| expanded.stdids |= set( | ||
| std + '#aux' for std in expanded.stdids) | ||
| expanded.stdids |= { | ||
| std + '#aux' for std in expanded.stdids} | ||
| if "standard_id like 'ivo://ivoa.net/std/sia#query-2.%'" in expanded.extra_fragments: | ||
@@ -641,6 +644,93 @@ expanded.extra_fragments.append( | ||
| f"ucd LIKE {{ucd{i}}}" for i in range(len(patterns))) | ||
| self._fillers = dict((f"ucd{index}", pattern) | ||
| for index, pattern in enumerate(patterns)) | ||
| self._fillers = {f"ucd{index}": pattern | ||
| for index, pattern in enumerate(patterns)} | ||
| class UAT(SubqueriedConstraint): | ||
| """ | ||
| A constraint selecting resources having UAT keywords as subjects. | ||
| The UAT (Unified Astronomy Thesaurus) is a hierarchical system | ||
| of concepts in astronomy. In the VO, its concept identifiers | ||
| are dashed strings, something like ``x-ray-transient-sources``. | ||
| The full list of identifiers is available from | ||
| http://www.ivoa.net/rdf/uat. | ||
| Note that not all data providers properly use UAT keywords in their | ||
| subjects even in 2025 (they should, though), and their keyword | ||
| assignments may not always be optimal. Consider doing free | ||
| text searches if UAT-based results are disappointing, and then | ||
| telling the respective data providers about missing keywords. | ||
| """ | ||
| _keyword = "uat" | ||
| _subquery_table = "rr.res_subject" | ||
| _condition = "res_subject in {query_terms}" | ||
| _uat = None | ||
| @classmethod | ||
| def _expand(cls, term, level, direction): | ||
| """ | ||
| Recursively expand term in the uat. | ||
| This returns a set of concepts that are ``level`` levels wider | ||
| or narrower (depending on the value of ``direction``) than term. | ||
| This function assumes the _uat class attribute has been filled | ||
| before; that is the case once a constraint has been constructed. | ||
| Parameters | ||
| ---------- | ||
| term: str | ||
| the start term | ||
| level: int | ||
| expand this many levels | ||
| direction: str | ||
| either ``wider`` to expand towards more general concepts | ||
| or ``narrower`` to expand toward more specialised concepts. | ||
| """ | ||
| result = {term} | ||
| new_concepts = cls._uat[term][direction] | ||
| if level: | ||
| for concept in new_concepts: | ||
| result |= cls._expand(concept, level-1, direction) | ||
| return result | ||
| def __init__(self, uat_keyword, *, expand_up=0, expand_down=0): | ||
| """ | ||
| Parameters | ||
| ---------- | ||
| uat_keyword: str | ||
| An identifier from http://www.ivoa.net/rdf/uat, i.e., a | ||
| string like type-ib-supernovae. Note that these are | ||
| always all-lowercase. | ||
| expand_up: int | ||
| In addition to the concept itself, also include expand_up | ||
| levels of parent concepts (this is probably rarely makes | ||
| sense beyond 1). | ||
| expand_down: int | ||
| In addition to the concept itself, also include expand_down | ||
| levels of more specialised concepts (this is usually a good | ||
| idea; having more than 10 here for now is equivalent to | ||
| infinity). | ||
| """ | ||
| if self.__class__._uat is None: | ||
| self.__class__._uat = vocabularies.get_vocabulary("uat")["terms"] | ||
| if uat_keyword not in self._uat: | ||
| raise dalq.DALQueryError( | ||
| f"{uat_keyword} does not identify an IVOA uat" | ||
| " concept (see http://www.ivoa.net/rdf/uat).") | ||
| query_terms = {uat_keyword} | ||
| if expand_up: | ||
| query_terms |= self._expand(uat_keyword, expand_up, "wider") | ||
| if expand_down: | ||
| query_terms |= self._expand(uat_keyword, expand_down, "narrower") | ||
| self._fillers = {"query_terms": query_terms} | ||
| class Spatial(SubqueriedConstraint): | ||
@@ -737,3 +827,3 @@ """ | ||
| def tomoc(s): | ||
| return _AsIs("MOC({}, {})".format(order, s)) | ||
| return _AsIs(f"MOC({order}, {s})") | ||
@@ -740,0 +830,0 @@ if isinstance(geom_spec, str): |
@@ -317,2 +317,3 @@ #!/usr/bin/env python | ||
| """ | ||
| def __init__(self, **kwargs): | ||
@@ -330,2 +331,3 @@ for k, v in kwargs.items(): | ||
| """ | ||
| def __init__(self, valdict): | ||
@@ -732,3 +734,3 @@ self.fieldnames = list(valdict.keys()) | ||
| 'doi:10.26093/cds/vizier.1337', | ||
| 'bibcode:2016yCat.1337....0G'} | ||
| } | ||
@@ -735,0 +737,0 @@ |
@@ -287,2 +287,32 @@ #!/usr/bin/env python | ||
| @pytest.mark.remote_data | ||
| class TestUATConstraint: | ||
| def test_basic(self): | ||
| cons = rtcons.UAT("solar-flares") | ||
| assert (cons.get_search_condition(FAKE_GAVO) | ||
| == "ivoid IN (SELECT DISTINCT ivoid FROM rr.res_subject WHERE res_subject in ('solar-flares'))") | ||
| def test_nonterm(self): | ||
| with pytest.raises(dalq.DALQueryError, match="solarium does not identify"): | ||
| rtcons.UAT("solarium") | ||
| def test_wider(self): | ||
| cons = rtcons.UAT("solar-flares", expand_up=2) | ||
| assert (cons.get_search_condition(FAKE_GAVO) | ||
| == "ivoid IN (SELECT DISTINCT ivoid FROM rr.res_subject WHERE res_subject in" | ||
| " ('solar-activity', 'solar-flares', 'solar-physics', 'solar-storm'))") | ||
| def test_narrower(self): | ||
| cons = rtcons.UAT("solar-activity", expand_down=1) | ||
| assert (cons.get_search_condition(FAKE_GAVO) | ||
| == "ivoid IN (SELECT DISTINCT ivoid FROM rr.res_subject WHERE res_subject in" | ||
| " ('solar-active-regions', 'solar-activity', 'solar-filaments', 'solar-flares'," | ||
| " 'solar-magnetic-bright-points', 'solar-prominences', 'solar-storm'))") | ||
| cons = rtcons.UAT("solar-activity", expand_down=2) | ||
| assert (cons.get_search_condition(FAKE_GAVO).startswith( | ||
| "ivoid IN (SELECT DISTINCT ivoid FROM rr.res_subject WHERE res_subject in" | ||
| " ('ephemeral-active-regions', 'quiescent-solar-prominence'," | ||
| " 'solar-active-region-filaments'")) | ||
| class TestSpatialConstraint: | ||
@@ -526,3 +556,3 @@ def test_point(self): | ||
| " author, datamodel, ivoid, keywords, servicetype," | ||
| " spatial, spectral, temporal, ucd, waveband.") | ||
| " spatial, spectral, temporal, uat, ucd, waveband.") | ||
@@ -619,5 +649,6 @@ def test_with_legacy_keyword(self): | ||
| time = rtcons.Temporal((50000, 60000)) | ||
| uat = rtcons.UAT('galaxies', expand_down=3) | ||
| result = registry.search( | ||
| text, author, servicetype, waveband, datamodel, | ||
| ivoid, ucd, moc, spectral, time | ||
| ivoid, ucd, moc, spectral, time, uat | ||
| ) | ||
@@ -624,0 +655,0 @@ assert result.fieldnames == ( |
| import inspect | ||
| import warnings | ||
| from functools import wraps | ||
| from typing import Dict, Iterable | ||
| from collections.abc import Iterable | ||
| from .protofeature import Feature | ||
@@ -11,3 +11,3 @@ | ||
| features: Dict[str, "Feature"] = { | ||
| features: dict[str, "Feature"] = { | ||
| 'cadc-tb-upload': Feature('cadc-tb-upload', | ||
@@ -14,0 +14,0 @@ 'https://wiki.ivoa.net/twiki/bin/view/IVOA/TAP-1_1-Next', |
@@ -29,3 +29,3 @@ """ | ||
| @functools.lru_cache() | ||
| @functools.lru_cache | ||
| def get_vocabulary(voc_name, force_update=False): | ||
@@ -65,3 +65,3 @@ """returns an IVOA vocabulary in its "desise" form. | ||
| with open(src_name, "r", encoding="utf-8") as f: | ||
| with open(src_name, encoding="utf-8") as f: | ||
| return json.load(f) | ||
@@ -68,0 +68,0 @@ |
@@ -15,3 +15,3 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| return '{}:{}:{}: {}: {}'.format(filename, pos[0], pos[1], name, message) | ||
| return f'{filename}:{pos[0]}:{pos[1]}: {name}: {message}' | ||
@@ -18,0 +18,0 @@ |
+1
-1
@@ -8,2 +8,2 @@ # Note that we need to fall back to the hard-coded version if either | ||
| except Exception: | ||
| version = '1.6.2' | ||
| version = '1.7' |
+4
-4
@@ -34,3 +34,3 @@ PyVO | ||
| Source code can be found `on GitHub <http://github.com/astropy/pyvo>`_ | ||
| Source code can be found `on GitHub <https://github.com/astropy/pyvo>`_ | ||
@@ -40,3 +40,3 @@ Installation and Requirements | ||
| Releases of PyVO are available from `PyPI <https://pypi.python.org/pypi/pyvo>`_ | ||
| Releases of PyVO are available from `PyPI <https://pypi.org/project/pyvo/>`_ | ||
| thus, it and its prerequisites can be most easily installed using ``pip``: | ||
@@ -56,3 +56,3 @@ | ||
| * `astropy <https://astropy.org>`__ (>=4.1) | ||
| * `requests <http://docs.python-requests.org/en/latest/>`_ | ||
| * `requests <https://docs.python-requests.org/en/latest/>`_ | ||
@@ -93,3 +93,3 @@ The following packages are optional dependencies and are required for the | ||
| Many instructive examples can be found in the `PyVO Documentation <http://pyvo.readthedocs.org>`_. | ||
| Many instructive examples can be found in the `PyVO Documentation <https://pyvo.readthedocs.io/en/latest/>`_. | ||
| Additional examples can be found in the examples directory. | ||
@@ -96,0 +96,0 @@ |
+2
-5
@@ -17,5 +17,2 @@ [tool:pytest] | ||
| ignore:numpy.core:DeprecationWarning | ||
| ignore::astropy.utils.iers.iers.IERSStaleWarning | ||
| ignore:Importing ErfaWarning:astropy.utils.exceptions.AstropyDeprecationWarning | ||
| ignore::astropy.utils.exceptions.ErfaWarning | ||
| ignore:pyvo.discover:pyvo.utils.prototype.PrototypeWarning | ||
@@ -59,5 +56,5 @@ | ||
| install_requires = | ||
| astropy>=4.1 | ||
| astropy>=4.2 | ||
| requests | ||
| python_requires = >=3.8 | ||
| python_requires = >=3.9 | ||
@@ -64,0 +61,0 @@ [options.extras_require] |
+4
-8
@@ -6,3 +6,3 @@ [tox] | ||
| envlist = | ||
| py{38,39,310,311,312,313}-test{,-alldeps,-oldestdeps,-devdeps}{,-online}{,-cov} | ||
| py{39,310,311,312,313}-test{,-alldeps,-oldestdeps,-devdeps}{,-online}{,-cov} | ||
| linkcheck | ||
@@ -17,3 +17,3 @@ codestyle | ||
| extras = | ||
| test: test | ||
| test | ||
| alldeps: all | ||
@@ -31,4 +31,2 @@ | ||
| devdeps: PIP_EXTRA_INDEX_URL = https://pypi.anaconda.org/scientific-python-nightly-wheels/simple https://pypi.anaconda.org/liberfa/simple https://pypi.anaconda.org/astropy/simple | ||
| # astropy doesn't yet have a 3.13 compatible release | ||
| py313: PIP_EXTRA_INDEX_URL = https://pypi.anaconda.org/liberfa/simple https://pypi.anaconda.org/astropy/simple | ||
@@ -42,9 +40,7 @@ deps = | ||
| # astropy doesn't yet have a 3.13 compatible release | ||
| py313: astropy>=0.0dev0 | ||
| oldestdeps: astropy==4.2 | ||
| oldestdeps: astropy==4.1 | ||
| # We set a suitably old numpy along with an old astropy, no need to pick up | ||
| # deprecations and errors due to their unmatching versions | ||
| oldestdeps: numpy==1.19 | ||
| oldestdeps: numpy==1.20 | ||
@@ -51,0 +47,0 @@ online: pytest-rerunfailures |
Sorry, the diff of this file is too big to display
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
3993596
61.05%306
13.75%25851
11.36%