Пример #1
0
def test_misc():
    cadc = Cadc()

    coords = '08h45m07.5s +54d18m00s'
    coords_ra = parse_coordinates(coords).fk5.ra.degree
    coords_dec = parse_coordinates(coords).fk5.dec.degree

    assert "SELECT * from caom2.Observation o join caom2.Plane p ON " \
           "o.obsID=p.obsID WHERE INTERSECTS( CIRCLE('ICRS', " \
           "{}, {}, 0.3), position_bounds) = 1 " \
           "AND (quality_flag IS NULL OR quality_flag != 'junk') " \
           "AND collection='CFHT' AND dataProductType='image'".\
           format(coords_ra, coords_dec) == \
           cadc._args_to_payload(**{'coordinates': coords,
                                    'radius': 0.3 * u.deg, 'collection':
                                        'CFHT',
                                    'data_product_type': 'image'})['query']

    # no collection or data_product_type
    assert "SELECT * from caom2.Observation o join caom2.Plane p ON " \
           "o.obsID=p.obsID WHERE INTERSECTS( CIRCLE('ICRS', " \
           "{}, {}, 0.3), position_bounds) = 1 AND (quality_flag IS NULL OR " \
           "quality_flag != 'junk')".format(coords_ra, coords_dec) ==  \
           cadc._args_to_payload(**{'coordinates': coords,
                                 'radius': '0.3 deg'})['query']
Пример #2
0
def test_misc(monkeypatch):
    dummyTapHandler = DummyTapHandler()
    monkeypatch.setattr(cadc_core, 'get_access_url', get_access_url_mock)
    cadc = CadcClass(tap_plus_handler=dummyTapHandler)

    class Result(object):
        pass

    result = Result()
    result._phase = 'RUN'
    with pytest.raises(RuntimeError):
        cadc._parse_result(result)

    result._phase = 'COMPLETED'
    result.results = 'WELL DONE'
    assert result.results == cadc._parse_result(result)
    coords = '08h45m07.5s +54d18m00s'
    coords_ra = parse_coordinates(coords).fk5.ra.degree
    coords_dec = parse_coordinates(coords).fk5.dec.degree

    assert "SELECT * from caom2.Observation o join caom2.Plane p ON " \
           "o.obsID=p.obsID WHERE INTERSECTS( CIRCLE('ICRS', " \
           "{}, {}, 0.3), position_bounds) = 1 " \
           "AND (quality_flag IS NULL OR quality_flag != 'junk') " \
           "AND collection='CFHT'".format(coords_ra, coords_dec) == \
           cadc._args_to_payload(**{'coordinates': coords,
                                 'radius': 0.3, 'collection': 'CFHT'})['query']

    # no collection
    assert "SELECT * from caom2.Observation o join caom2.Plane p ON " \
           "o.obsID=p.obsID WHERE INTERSECTS( CIRCLE('ICRS', " \
           "{}, {}, 0.3), position_bounds) = 1 AND (quality_flag IS NULL OR " \
           "quality_flag != 'junk')".format(coords_ra, coords_dec) ==  \
           cadc._args_to_payload(**{'coordinates': coords,
                                 'radius': 0.3})['query']
Пример #3
0
def test_misc(monkeypatch):
    dummyTapHandler = DummyTapHandler()
    monkeypatch.setattr(cadc_core, 'get_access_url', get_access_url_mock)
    cadc = Cadc(tap_plus_handler=dummyTapHandler)

    class Result(object):
        pass
    result = Result()
    result._phase = 'RUN'
    with pytest.raises(RuntimeError):
        cadc._parse_result(result)

    result._phase = 'COMPLETED'
    result.results = 'WELL DONE'
    assert result.results == cadc._parse_result(result)
    coords = '08h45m07.5s +54d18m00s'
    coords_ra = parse_coordinates(coords).ra.degree
    coords_dec = parse_coordinates(coords).dec.degree

    assert "SELECT * from caom2.Observation o join caom2.Plane p ON " \
           "o.obsID=p.obsID WHERE INTERSECTS( CIRCLE('ICRS', " \
           "{}, {}, 0.3), position_bounds) = 1 " \
           "AND (quality_flag IS NULL OR quality_flag != 'junk') " \
           "AND collection='CFHT'".format(coords_ra, coords_dec) == \
           cadc._args_to_payload(**{'coordinates': coords,
                                 'radius': 0.3, 'collection': 'CFHT'})['query']

    # no collection
    assert "SELECT * from caom2.Observation o join caom2.Plane p ON " \
           "o.obsID=p.obsID WHERE INTERSECTS( CIRCLE('ICRS', " \
           "{}, {}, 0.3), position_bounds) = 1 AND (quality_flag IS NULL OR " \
           "quality_flag != 'junk')".format(coords_ra, coords_dec) ==  \
           cadc._args_to_payload(**{'coordinates': coords,
                                 'radius': 0.3})['query']
Пример #4
0
def handle_coordinates(url, key, coordinates):
    """ Handler function for coordinates """
    assert(key == "coordinates")
    coordinates = commons.parse_coordinates(coordinates)
    if coordinates is not None:
        return "%s/ra=%f/dec=%f" % (url, coordinates.ra.deg, coordinates.dec.deg)
    return url
Пример #5
0
    def addTarget(self, target):
        """Add target to archiveSearch object.

        Parameters
        ----------
        target : str or list
            Target to query the ALMA archive for. Can be either a string
            indicating a source name (e.g. 'M87') or a list indicating a
            region to search consisting of (coordinates, radius). The
            coordinates element can be either a string or an
            astropy.coordinates object and the radius element can be either a
            string or an astropy.units.Quantity object.
        """
        targetType = type(target)

        if targetType == str:  # source name
            self.targets[target] = target
            self.isObjectQuery[target] = True
        elif targetType == list:  # region
            if type(target[0]) != SkyCoord:
                target[0] = commons.parse_coordinates(target[0])
            if type(target[1]) != Angle:
                target[1] = Angle(target[1])

            targetStr = 'coord=({:} {:}) radius={:}deg'
            targetStr = targetStr.format(target[0].ra, target[0].dec,
                                         target[1].deg)

            self.targets[targetStr] = target
            self.isObjectQuery[targetStr] = False
        else:
            msg = 'Cannot work with targets of type {:}'.format(targetType)
            raise TypeError(msg)
Пример #6
0
def _parse_coordinates(coordinates):
    try:
        coordinates = commons.parse_coordinates(coordinates)
        # now c has some subclass of astropy.coordinate
        # get ra, dec and frame
        return _get_frame_coords(coordinates)
    except (u.UnitsError, TypeError):
        raise ValueError("Coordinates not specified correctly")
Пример #7
0
 def __getCoordInput(self, value, msg):
     if not (isinstance(value, str) or isinstance(value,
                                                  commons.CoordClasses)):
         raise ValueError(f"{msg} must be either a string or astropy.coordinates")
     if isinstance(value, str):
         c = commons.parse_coordinates(value)
         return c
     else:
         return value
Пример #8
0
 def __getCoordInput(self, value, msg):
     if not (isinstance(value, str) or isinstance(value, commons.CoordClasses)):
         raise ValueError(
             str(msg) + " must be either a string or astropy.coordinates")
     if isinstance(value, str):
         c = commons.parse_coordinates(value)
         return c
     else:
         return value
Пример #9
0
    def query_region_async(self, table, coordinates, radius, *, get_query_payload=False, cache=None,
                           **criteria):
        """
        Filter a table using a cone search around specified coordinates

        Parameters
        ----------
        table : str
            The name of the table to query. A list of the tables on the Exoplanet Archive can be
            found on the documentation pages [1]_, [2]_.
        coordinates : str or `~astropy.coordinates`
            The coordinates around which to query.
        radius : str or `~astropy.units.Quantity`
            The radius of the cone search. Assumed to be have units of degrees if not provided as
            a ``Quantity``.
        get_query_payload : bool, optional
            Just return the dict of HTTP request parameters. Defaults to ``False``.
        cache : bool, optional
            Should the request result be cached? This can be useful for large repeated queries,
            but since the data in the archive is updated regularly, this defaults to ``False``.
        **criteria
            Any other filtering criteria to apply. These are described in detail in the archive
            documentation [1]_,[2]_ but some examples include ``select="*"`` to return all columns of
            the queried table or ``where=pl_name='K2-18 b'`` to filter a specific column.

        Returns
        -------
        response : `requests.Response`
            The HTTP response returned from the service.

        References
        ----------

        .. [1] `NASA Exoplanet Archive TAP Documentation
           <https://exoplanetarchive.ipac.caltech.edu/docs/TAP/usingTAP.html>`_
        .. [2] `NASA Exoplanet Archive API Documentation
           <https://exoplanetarchive.ipac.caltech.edu/docs/program_interfaces.html>`_
        """
        # Checks if coordinate strings is parsable as an astropy.coordinates object
        coordinates = commons.parse_coordinates(coordinates)

        # if radius is just a number we assume degrees
        if isinstance(radius, (int, float)):
            radius = radius * u.deg
        radius = coord.Angle(radius)

        criteria["ra"] = coordinates.ra.deg
        criteria["dec"] = coordinates.dec.deg
        criteria["radius"] = "{0} degree".format(radius.deg)

        # Runs the query method defined above, but with added region filter
        return self.query_criteria_async(
            table, get_query_payload=get_query_payload, cache=cache, **criteria,
        )
Пример #10
0
    def _args_to_payload(self, coordinate, radius=None):
        """
        Accepts the query parameters and returns a dictionary
        suitable to be sent as data via a HTTP POST request.

        Parameters
        ----------
        coordinate : str
            Can be either the name of an object or a coordinate string
            If a name, must be resolvable by NED, SIMBAD, 2MASS, or SWAS.
            Examples of acceptable coordinate strings, can be found `here
            <https://irsa.ipac.caltech.edu/applications/DUST/docs/coordinate.html>`_
        radius : str / `~astropy.units.Quantity`, optional
            The size of the region to include in the dust query, in radian,
            degree or hour as per format specified by
            `~astropy.coordinates.Angle` or `~astropy.units.Quantity`.
            Defaults to 5 degrees.

        Returns
        -------
        payload : dict
            A dictionary that specifies the data for an HTTP POST request
        """
        if isinstance(coordinate, str):
            try:
                # If the coordinate is a resolvable name, pass that name
                # directly to irsa_dust because it can handle it (and that
                # changes the return value associated metadata)
                C = commons.ICRSCoord.from_name(coordinate)
                payload = {"locstr": coordinate}
            except coordinates.name_resolve.NameResolveError:
                C = commons.parse_coordinates(coordinate).transform_to('fk5')
                # check if this is resolvable?
                payload = {"locstr": "{0} {1}".format(C.ra.deg, C.dec.deg)}
        elif isinstance(coordinate, coordinates.SkyCoord):
            C = coordinate.transform_to('fk5')
            payload = {"locstr": "{0} {1}".format(C.ra.deg, C.dec.deg)}
        # check if radius is given with proper units
        if radius is not None:
            reg_size = coordinates.Angle(radius).deg
            # check if radius falls in the acceptable range
            if reg_size < 2 or reg_size > 37.5:
                raise ValueError("Radius (in any unit) must be in the"
                                 " range of 2.0 to 37.5 degrees")
            payload["regSize"] = reg_size
        return payload
Пример #11
0
    def query_region(self,
                     coordinate,
                     radius,
                     *,
                     n_obs=10,
                     columns='*',
                     **kwargs):
        """
        Get the observation metadata from a given region

        Parameters
        ----------
        coordinate : string / `astropy.coordinates`
            the identifier or coordinates around which to query
        radius : int / `~astropy.units.Quantity`
            the radius of the region
        n_obs : int, optional
            the number of observations
        columns : str, optional
            the columns to retrieve from the data table
        kwargs : dict
            passed to `query_hsa_tap`

        Returns
        -------
        A table object with the list of observations in the region
        """
        r = radius
        if not isinstance(radius, u.Quantity):
            r = radius * u.deg
        coord = commons.parse_coordinates(coordinate).icrs

        query = (
            f"select top {n_obs} {columns} from hsa.v_active_observation "
            f"where contains("
            f"point('ICRS', hsa.v_active_observation.ra, hsa.v_active_observation.dec), "
            f"circle('ICRS', {coord.ra.degree},{coord.dec.degree},{r.to(u.deg).value}))=1"
        )
        return self.query_hsa_tap(query, **kwargs)
Пример #12
0
    def test_get_images_against_AS(self):
        cadc = Cadc()
        coords = '08h45m07.5s +54d18m00s'
        radius = 0.05 * u.deg

        # Compare results from cadc advanced search to get_images
        query = cadc._args_to_payload(**{
            'coordinates': coords,
            'radius': radius,
            'data_product_type': 'image'
        })['query']
        result = cadc.exec_sync(query)
        uri_list = [uri.decode('ascii') for uri in result['publisherID']]
        access_url = 'https://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/en/download'
        icrs_coords = parse_coordinates(coords).icrs
        data = {
            'uris':
            ' '.join(uri_list),
            'params':
            'cutout=Circle ICRS {} {} {}'.format(icrs_coords.ra.degree,
                                                 icrs_coords.dec.degree,
                                                 radius.value),
            'method':
            'URL List'
        }

        resp_urls = requests.post(access_url, data).text.split('\r\n')

        # Filter out the errors and empty strings
        filtered_resp_urls = list(
            filter(lambda url: not url.startswith('ERROR') and url != '',
                   resp_urls))

        # This function should return nearly the same urls
        image_urls = cadc.get_images(coords, radius, get_url_list=True)

        assert len(filtered_resp_urls) == len(image_urls)
Пример #13
0
def test_get_image_list():
    def get(*args, **kwargs):
        class CapsResponse(object):
            def __init__(self):
                self.status_code = 200
                self.content = b''

            def raise_for_status(self):
                pass

        return CapsResponse()

    class Params(object):
        def __init__(self, **param_dict):
            self.__dict__.update(param_dict)

    coords = '08h45m07.5s +54d18m00s'
    coords_ra = parse_coordinates(coords).fk5.ra.degree
    coords_dec = parse_coordinates(coords).fk5.dec.degree
    radius = 0.1*u.deg

    uri = 'im_an_ID'
    run_id = 'im_a_RUNID'
    pos = 'CIRCLE {} {} {}'.format(coords_ra, coords_dec, radius.value)

    service_def1 = Mock()
    service_def1.access_url = \
        b'https://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/caom2ops/sync'
    service_def1.input_params = [Params(name='ID', value=uri),
                                 Params(name='RUNID', value=run_id)]

    service_def2 = Mock()
    service_def2.access_url = \
        b'https://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/caom2ops/async'
    service_def2.input_params = [Params(name='ID', value=uri),
                                 Params(name='RUNID', value=run_id)]

    result = Mock()
    service_def_list = [service_def1, service_def2]
    result.bysemantics.return_value = service_def_list

    with patch('pyvo.dal.adhoc.DatalinkResults.from_result_url') as dl_results_mock:
        dl_results_mock.return_value = result
        cadc = Cadc()
        cadc._request = get  # Mock the request
        url_list = cadc.get_image_list(
            {'publisherID': ['ivo://cadc.nrc.ca/foo']}, coords, radius)

        assert len(url_list) == 1

        params = parse_qs(urlsplit(url_list[0]).query)

        assert params['ID'][0] == uri
        assert params['RUNID'][0] == run_id
        assert params['POS'][0] == pos

    with pytest.raises(TypeError):
        cadc.get_image_list(None)
    with pytest.raises(AttributeError):
        cadc.get_image_list(None, coords, radius)
    with pytest.raises(TypeError):
        cadc.get_image_list({'publisherID': [
            'ivo://cadc.nrc.ca/foo']}, coords, 0.1)
Пример #14
0
    def query_region_async(self,
                           coordinates,
                           radius=1 * u.arcmin,
                           equinox='J2000.0',
                           get_query_payload=False):
        """
        Serves the same purpose as `~NedClass.query_region` but returns the
        raw HTTP response rather than the `astropy.table.Table` object.

        Parameters
        ----------
        coordinates : str or `astropy.coordinates` object
            The target around which to search. It may be specified as a
            string in which case it is resolved using online services or as
            the appropriate `astropy.coordinates` object. ICRS coordinates
            may also be entered as strings as specified in the
            `astropy.coordinates` module.
        radius : str or `~astropy.units.Quantity` object, optional
            The string must be parsable by `astropy.coordinates.Angle`. The
            appropriate `~astropy.units.Quantity` object from
            `astropy.units` may also be used. Defaults to 1 arcmin.
        equinox : str, optional
            The equinox may be either J2000.0 or B1950.0. Defaults to J2000.0
        get_query_payload : bool, optional
            if set to `True` then returns the dictionary sent as the HTTP
            request.  Defaults to `False`.

        Returns
        -------
        response : `requests.Response`
            The HTTP response returned from the service

        """
        request_payload = self._request_payload_init()
        self._set_input_options(request_payload)
        self._set_output_options(request_payload)
        # if its a name then query near name
        if not commons._is_coordinate(coordinates):
            request_payload['objname'] = coordinates
            request_payload['search_type'] = 'Near Name Search'
            request_payload['radius'] = coord.Angle(radius).arcmin
        else:
            try:
                c = commons.parse_coordinates(coordinates)
                if c.frame.name == 'galactic':
                    request_payload['in_csys'] = 'Galactic'
                    request_payload['lon'] = c.l.degree
                    request_payload['lat'] = c.b.degree
                # for any other, convert to ICRS and send
                else:
                    request_payload['in_csys'] = 'Equatorial'
                    ra, dec = commons.coord_to_radec(c)
                    request_payload['lon'] = ra
                    request_payload['lat'] = dec
                request_payload['search_type'] = 'Near Position Search'
                request_payload['in_equinox'] = equinox
                request_payload['radius'] = coord.Angle(radius).arcmin
            except (u.UnitsError, TypeError):
                raise TypeError("Coordinates not specified correctly")
        if get_query_payload:
            return request_payload
        response = self._request("GET",
                                 url=Ned.OBJ_SEARCH_URL,
                                 params=request_payload,
                                 timeout=Ned.TIMEOUT)
        return response
Пример #15
0
    def query_region_async(self,
                           coordinate=None,
                           where=None,
                           mission=None,
                           dataset=None,
                           table=None,
                           columns=None,
                           width=None,
                           height=None,
                           action='search',
                           intersect='OVERLAPS',
                           most_centered=False):
        """
        For certain missions, this function can be used to search for image and
        catalog files based on a point, a box (bounded by great circles) and/or
        an SQL-like ``where`` clause.

        If ``coordinates`` is specified, then the optional ``width`` and
        ``height`` arguments control the width and height of the search
        box. If neither ``width`` nor ``height`` are provided, then the
        search area is a point. If only one of ``width`` or ``height`` are
        specified, then the search area is a square with that side length
        centered at the coordinate.

        Parameters
        ----------
        coordinate : str, `astropy.coordinates` object
            Gives the position of the center of the box if performing a box
            search. If it is a string, then it must be a valid argument to
            `~astropy.coordinates.SkyCoord`. Required if ``where`` is absent.
        where : str
            SQL-like query string. Required if ``coordinates`` is absent.
        mission : str
            The mission to be used (if not the default mission).
        dataset : str
            The dataset to be used (if not the default dataset).
        table : str
            The table to be queried (if not the default table).
        columns : str, list
            A space-separated string or a list of strings of the names of the
            columns to return.
        width : str or `~astropy.units.Quantity` object
            Width of the search box if ``coordinates`` is present.

            The string must be parsable by `~astropy.coordinates.Angle`. The
            appropriate `~astropy.units.Quantity` object from `astropy.units`
            may also be used.
        height : str, `~astropy.units.Quantity` object
            Height of the search box if ``coordinates`` is present.

            The string must be parsable by `~astropy.coordinates.Angle`. The
            appropriate `~astropy.units.Quantity` object from `astropy.units`
            may also be used.
        intersect : ``'COVERS'``, ``'ENCLOSED'``, ``'CENTER'``, ``'OVERLAPS'``
            Spatial relationship between search box and image footprint.

            ``'COVERS'``: X must completely contain S. Equivalent to
            ``'CENTER'`` and ``'OVERLAPS'`` if S is a point.

            ``'ENCLOSED'``: S must completely contain X. If S is a point, the
            query will always return an empty image table.

            ``'CENTER'``: X must contain the center of S. If S is a point, this
            is equivalent to ``'COVERS'`` and ``'OVERLAPS'``.

            ``'OVERLAPS'``: The intersection of S and X is non-empty. If S is a
            point, this is equivalent to ``'CENTER'`` and ``'COVERS'``.
        most_centered : bool
            If True, then only the most centered image is returned.
        action : ``'search'``, ``'data'``, or ``'sia'``
            The action to perform at the server.  The default is ``'search'``,
            which returns a table of the available data.  ``'data'`` requires
            advanced path construction that is not yet supported. ``'sia'``
            provides access to the 'simple image access' IVOA protocol

        Returns
        -------
        response : `~requests.Response`
            The HTTP response returned from the service
        """

        if coordinate is None and where is None:
            raise InvalidQueryError(
                'At least one of `coordinate` or `where` is required')

        intersect = intersect.upper()
        if intersect not in ('COVERS', 'ENCLOSED', 'CENTER', 'OVERLAPS'):
            raise InvalidQueryError(
                "Invalid value for `intersects` " +
                "(must be 'COVERS', 'ENCLOSED', 'CENTER', or 'OVERLAPS')")

        if action not in ('sia', 'data', 'search'):
            raise InvalidQueryError("Valid actions are: sia, data, search.")
        if action == 'data':
            raise NotImplementedError(
                "The action='data' option is a placeholder for future " +
                "functionality.")

        args = {'INTERSECT': intersect}

        # Note: in IBE, if 'mcen' argument is present, it is true.
        # If absent, it is false.
        if most_centered:
            args['mcen'] = '1'

        if coordinate is not None:
            c = commons.parse_coordinates(coordinate).transform_to(coord.ICRS)
            args['POS'] = '{0},{1}'.format(c.ra.deg, c.dec.deg)
            if width and height:
                args['SIZE'] = '{0},{1}'.format(
                    coord.Angle(width).value,
                    coord.Angle(height).value)
            elif width or height:
                args['SIZE'] = str(coord.Angle(width or height).value)

        if where:
            args['where'] = where

        if columns:
            if isinstance(columns, str):
                columns = columns.split()
            args['columns'] = ','.join(columns)

        url = "{URL}{action}/{mission}/{dataset}/{table}".format(
            URL=self.URL,
            action=action,
            mission=mission or self.MISSION,
            dataset=dataset or self.DATASET,
            table=table or self.TABLE)

        return self._request('GET', url, args, timeout=self.TIMEOUT)