diff --git a/astropy_helpers b/astropy_helpers index 5fd32d0edc..161773fa72 160000 --- a/astropy_helpers +++ b/astropy_helpers @@ -1 +1 @@ -Subproject commit 5fd32d0edc34f94de9640fd20865cfe5d605e499 +Subproject commit 161773fa72d916c498e0a2a513ecc24460244ac8 diff --git a/astroquery/lcogt/__init__.py b/astroquery/lcogt/__init__.py new file mode 100644 index 0000000000..3966a577b8 --- /dev/null +++ b/astroquery/lcogt/__init__.py @@ -0,0 +1,37 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +""" +LCOGT public archive Query Tool +=============== + +This module contains various methods for querying +LCOGT data archive as hosted by IPAC. +""" +from astropy import config as _config + + +class Conf(_config.ConfigNamespace): + """ + Configuration parameters for `astroquery.irsa`. + """ + + server = _config.ConfigItem( + 'http://lcogtarchive.ipac.caltech.edu/cgi-bin/Gator/nph-query', + 'Name of the LCOGT archive as hosted by IPAC to use.' + ) + row_limit = _config.ConfigItem( + 500, + 'Maximum number of rows to retrieve in result' + ) + timeout = _config.ConfigItem( + 60, + 'Time limit for connecting to the LCOGT IPAC server.' + ) + +conf = Conf() + + +from .core import Lcogt, LcogtClass + +__all__ = ['Lcogt', 'LcogtClass', + 'Conf', 'conf', + ] diff --git a/astroquery/lcogt/core.py b/astroquery/lcogt/core.py new file mode 100644 index 0000000000..417b500b86 --- /dev/null +++ b/astroquery/lcogt/core.py @@ -0,0 +1,436 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +""" +LCOGT +==== + +API from + +http://lcogtarchive.ipac.caltech.edu/docs/catsearch.html + +The URL of the LCOGT catalog query service, CatQuery, is + + http://lcogtarchive.ipac.caltech.edu/cgi-bin/Gator/nph-query + +The service accepts the following keywords, which are analogous to the search +fields on the Gator search form: + + +spatial Required Type of spatial query: Cone, Box, Polygon, and NONE + +polygon Convex polygon of ra dec pairs, separated by comma(,) + Required if spatial=polygon + +radius Cone search radius + Optional if spatial=Cone, otherwise ignore it + (default 10 arcsec) + +radunits Units of a Cone search: arcsec, arcmin, deg. + Optional if spatial=Cone + (default='arcsec') + +size Width of a box in arcsec + Required if spatial=Box. + +objstr Target name or coordinate of the center of a spatial + search center. Target names must be resolved by + SIMBAD or NED. + + Required only when spatial=Cone or spatial=Box. + + Examples: 'M31' + '00 42 44.3 -41 16 08' + '00h42m44.3s -41d16m08s' + +catalog Required Catalog name in the LCOGT Archive. The database of photometry + can be found using lco_cat and the database of image metadata is + found using lco_img. + +outfmt Optional Defines query's output format. + 6 - returns a program interface in XML + 3 - returns a VO Table (XML) + 2 - returns SVC message + 1 - returns an ASCII table + 0 - returns Gator Status Page in HTML (default) + +desc Optional Short description of a specific catalog, which will + appear in the result page. + +order Optional Results ordered by this column. + +selcols Optional Select specific columns to be returned. The default + action is to return all columns in the queried catalog. + To find the names of the columns in the LCOGT Archive databases, + please read Photometry Table column descriptions [http://lcogtarchive.ipac.caltech.edu/docs/lco_cat_dd.html] + and Image Table column descriptions [http://lcogtarchive.ipac.caltech.edu/docs/lco_img_dd.html]. + +constraint Optional User defined query constraint(s) + Note: The constraint should follow SQL syntax. + +""" +from __future__ import print_function, division + +import warnings +import xml.etree.ElementTree as tree +import logging + +from astropy.extern import six +import astropy.units as u +import astropy.coordinates as coord +import astropy.io.votable as votable + +from ..query import BaseQuery +from ..utils import commons, async_to_sync +from . import conf +from ..exceptions import TableParseError + +__all__ = ['Lcogt', 'LcogtClass'] + + +@async_to_sync +class LcogtClass(BaseQuery): + LCOGT_URL = conf.server + TIMEOUT = conf.timeout + ROW_LIMIT = conf.row_limit + + @property + def catalogs(self): + """ immutable catalog listing """ + return {'lco_cat' : 'Photometry archive from LCOGT', + 'lco_img' : 'Image metadata archive from LCOGT'} + + def query_object_async(self, objstr, catalog=None, cache=True, + get_query_payload=False): + """ + Serves the same function as `query_object`, but + only collects the reponse from the LCOGT IPAC archive and returns. + + Parameters + ---------- + objstr : str + name of object to be queried + catalog : str + name of the catalog to use. 'lco_img' for image meta data; + 'lco_cat' for photometry. + + Returns + ------- + response : `requests.Response` + Response of the query from the server + """ + if catalog is None: + raise ValueError("Catalogue name is required!") + if catalog not in self.catalogs: + raise ValueError("Catalog name must be one of {0}" + .format(self.catalogs)) + + request_payload = self._args_to_payload(catalog) + request_payload['objstr'] = objstr + if get_query_payload: + return request_payload + + response = self._request(method='GET', url=self.LCOGT_URL, + params=request_payload, timeout=self.TIMEOUT, + cache=cache) + return response + + + def query_region_async(self, coordinates=None, catalog=None, + spatial='Cone', radius=10*u.arcsec, width=None, + polygon=None, get_query_payload=False, cache=True, + ): + """ + This function serves the same purpose as + :meth:`~astroquery.irsa.LcogtClass.query_region`, but returns the raw + HTTP response rather than the results in a `~astropy.table.Table`. + + Parameters + ---------- + coordinates : str, `astropy.coordinates` object + Gives the position of the center of the cone or box if + performing a cone or box search. The string can give coordinates + in various coordinate systems, or the name of a source that will + be resolved on the server (see `here + `_ for more + details). Required if spatial is ``'Cone'`` or ``'Box'``. Optional + if spatial is ``'Polygon'``. + catalog : str + The catalog to be used. Either ``'lco_img'`` for image metadata or + ``'lco_cat'`` for photometry. + spatial : str + Type of spatial query: ``'Cone'``, ``'Box'``, ``'Polygon'``, and + ``'All-Sky'``. If missing then defaults to ``'Cone'``. + radius : str or `~astropy.units.Quantity` object, [optional for \\ + spatial is ``'Cone'``] + The string must be parsable by `~astropy.coordinates.Angle`. The + appropriate `~astropy.units.Quantity` object from + `astropy.units` may also be used. Defaults to 10 arcsec. + width : str, `~astropy.units.Quantity` object [Required for spatial \\ + is ``'Polygon'``.] + The string must be parsable by `~astropy.coordinates.Angle`. The + appropriate `~astropy.units.Quantity` object from `astropy.units` + may also be used. + polygon : list, [Required for spatial is ``'Polygon'``] + A list of ``(ra, dec)`` pairs (as tuples), in decimal degrees, + outlinining the polygon to search in. It can also be a list of + `astropy.coordinates` object or strings that can be parsed by + `astropy.coordinates.ICRS`. + get_query_payload : bool, optional + If `True` then returns the dictionary sent as the HTTP request. + Defaults to `False`. + + Returns + ------- + response : `requests.Response` + The HTTP response returned from the service + """ + if catalog is None: + raise ValueError("Catalogue name is required!") + if catalog not in self.catalogs: + raise ValueError("Catalog name must be one of {0}" + .format(self.catalogs)) + + + request_payload = self._args_to_payload(catalog) + request_payload.update(self._parse_spatial(spatial=spatial, + coordinates=coordinates, + radius=radius, width=width, + polygon=polygon)) + + if get_query_payload: + return request_payload + response = self._request(method='GET', url=self.LCOGT_URL, + params=request_payload, timeout=self.TIMEOUT, + cache=cache) + return response + + def _parse_spatial(self, spatial, coordinates, radius=None, width=None, + polygon=None): + """ + Parse the spatial component of a query + + Parameters + ---------- + spatial : str + The type of spatial query. Must be one of: ``'Cone'``, ``'Box'``, + ``'Polygon'``, and ``'All-Sky'``. + coordinates : str, `astropy.coordinates` object + Gives the position of the center of the cone or box if + performing a cone or box search. The string can give coordinates + in various coordinate systems, or the name of a source that will + be resolved on the server (see `here + `_ for more + details). Required if spatial is ``'Cone'`` or ``'Box'``. Optional + if spatial is ``'Polygon'``. + radius : str or `~astropy.units.Quantity` object, [optional for spatial is ``'Cone'``] + The string must be parsable by `~astropy.coordinates.Angle`. The + appropriate `~astropy.units.Quantity` object from `astropy.units` + may also be used. Defaults to 10 arcsec. + width : str, `~astropy.units.Quantity` object [Required for spatial is ``'Polygon'``.] + The string must be parsable by `~astropy.coordinates.Angle`. The + appropriate `~astropy.units.Quantity` object from `astropy.units` + may also be used. + polygon : list, [Required for spatial is ``'Polygon'``] + A list of ``(ra, dec)`` pairs as tuples of + `astropy.coordinates.Angle`s outlinining the polygon to search in. + It can also be a list of `astropy.coordinates` object or strings + that can be parsed by `astropy.coordinates.ICRS`. + + Returns + ------- + payload_dict : dict + """ + + request_payload = {} + + if spatial == 'All-Sky': + spatial = 'NONE' + elif spatial in ['Cone', 'Box']: + if not commons._is_coordinate(coordinates): + request_payload['objstr'] = coordinates + else: + request_payload['objstr'] = _parse_coordinates(coordinates) + if spatial == 'Cone': + radius = _parse_dimension(radius) + request_payload['radius'] = radius.value + request_payload['radunits'] = radius.unit.to_string() + else: + width = _parse_dimension(width) + request_payload['size'] = width.to(u.arcsec).value + elif spatial == 'Polygon': + if coordinates is not None: + request_payload['objstr'] = (coordinates if not + commons._is_coordinate(coordinates) + else + _parse_coordinates(coordinates)) + try: + coordinates_list = [_parse_coordinates(c) for c in polygon] + except (ValueError, TypeError): + coordinates_list = [_format_decimal_coords(*_pair_to_deg(pair)) + for pair in polygon] + request_payload['polygon'] = ','.join(coordinates_list) + else: + raise ValueError("Unrecognized spatial query type. " + "Must be one of `Cone`, `Box`, " + "`Polygon`, or `All-Sky`.") + + request_payload['spatial'] = spatial + + return request_payload + + def _args_to_payload(self, catalog): + """ + Sets the common parameters for all cgi -queries + + Parameters + ---------- + catalog : str + The name of the catalog to query. + + Returns + ------- + request_payload : dict + """ + request_payload = dict(catalog=catalog, + outfmt=3, + spatial=None, + outrows=Lcogt.ROW_LIMIT) + return request_payload + + def _parse_result(self, response, verbose=False): + """ + Parses the results form the HTTP response to `~astropy.table.Table`. + + Parameters + ---------- + response : `requests.Response` + The HTTP response object + verbose : bool, optional + Defaults to `False`. When true it will display warnings whenever + the VOtable returned from the Service doesn't conform to the + standard. + + Returns + ------- + table : `~astropy.table.Table` + """ + if not verbose: + commons.suppress_vo_warnings() + + content = response.text + logging.debug(content) + + # Check if results were returned + if 'The catalog is not in the list' in content: + raise Exception("Catalogue not found") + + # Check that object name was not malformed + if 'Either wrong or missing coordinate/object name' in content: + raise Exception("Malformed coordinate/object name") + + # Check that the results are not of length zero + if len(content) == 0: + raise Exception("The LCOGT server sent back an empty reply") + + # Read it in using the astropy VO table reader + try: + first_table = votable.parse(six.BytesIO(response.content), + pedantic=False).get_first_table() + except Exception as ex: + self.response = response + self.table_parse_error = ex + raise TableParseError("Failed to parse LCOGT votable! The raw " + " response can be found in self.response," + " and the error in self.table_parse_error.") + + # Convert to astropy.table.Table instance + table = first_table.to_table() + + # Check if table is empty + if len(table) == 0: + warnings.warn("Query returned no results, so the table will be empty") + + return table + + def list_catalogs(self): + """ + Return a dictionary of the catalogs in the LCOGT Gator tool. + + Returns + ------- + catalogs : dict + A dictionary of catalogs where the key indicates the catalog name to + be used in query functions, and the value is the verbose description + of the catalog. + """ + return self.catalogs + + def print_catalogs(self): + """ + Display a table of the catalogs in the LCOGT Gator tool. + """ + for catname in self.catalogs: + print("{:30s} {:s}".format(catname, catalogs[catname])) + +Lcogt = LcogtClass() + + +def _parse_coordinates(coordinates): +# borrowed from commons.parse_coordinates as from_name wasn't required in this case + if isinstance(coordinates, six.string_types): + try: + c = coord.SkyCoord(coordinates, frame='icrs') + warnings.warn("Coordinate string is being interpreted as an ICRS coordinate.") + except u.UnitsError as ex: + warnings.warn("Only ICRS coordinates can be entered as strings\n" + "For other systems please use the appropriate " + "astropy.coordinates object") + raise ex + elif isinstance(coordinates, commons.CoordClasses): + c = coordinates + else: + raise TypeError("Argument cannot be parsed as a coordinate") + c_icrs = c.transform_to(coord.ICRS) + formatted_coords = _format_decimal_coords(c_icrs.ra.degree, c_icrs.dec.degree) + return formatted_coords + +def _pair_to_deg(pair): + """ Turn a pair of floats, Angles, or Quantities into pairs of float degrees """ + + # unpack + lon, lat = pair + + if hasattr(lon, 'degree') and hasattr(lat, 'degree'): + pair = (lon.degree, lat.degree) + elif hasattr(lon, 'to') and hasattr(lat, 'to'): + pair = [lon, lat] + for ii, ang in enumerate((lon, lat)): + if ang.unit.is_equivalent(u.degree): + pair[ii] = ang.to(u.degree).value + elif ang.unit.is_equivalent(u.hour): + warnings.warn("Assuming angle specified with 'hour' units means 'hourangle'. " + "This is an astropy < 0.3 warning.") + pair[ii] = (ang.value * u.hourangle).to(u.degree) + else: + warnings.warn("Polygon endpoints are being interpreted as RA/Dec pairs specified in decimal degree units.") + return tuple(pair) + + +def _format_decimal_coords(ra, dec): + """ + Print *decimal degree* RA/Dec values in an IPAC-parseable form + """ + return '{0} {1:+}'.format(ra, dec) + + +def _parse_dimension(dim): + if isinstance(dim, u.Quantity) and dim.unit in u.deg.find_equivalent_units(): + if dim.unit not in ['arcsec', 'arcmin', 'deg']: + dim = dim.to(u.degree) + # otherwise must be an Angle or be specified in hours... + else: + try: + new_dim = commons.parse_radius(dim) + dim = u.Quantity(new_dim.degree, u.Unit('degree')) + except (u.UnitsError, coord.errors.UnitsError, AttributeError): + raise u.UnitsError("Dimension not in proper units") + return dim diff --git a/astroquery/lcogt/tests/__init__.py b/astroquery/lcogt/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/astroquery/lcogt/tests/data/Box.xml b/astroquery/lcogt/tests/data/Box.xml new file mode 100644 index 0000000000..063788931a --- /dev/null +++ b/astroquery/lcogt/tests/data/Box.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
10.68473741.26903500h42m44.34s41d16m08.53s0.080.078700424433+41160859.4530.0510.0525385.68.6680.0500.0515089.98.4750.0500.0513684.8EEE22211100055665520n1997-10-248121.174-21.573000.78500.19300.97800
+
+
diff --git a/astroquery/lcogt/tests/data/Cone.xml b/astroquery/lcogt/tests/data/Cone.xml new file mode 100644 index 0000000000..d9d8537846 --- /dev/null +++ b/astroquery/lcogt/tests/data/Cone.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
10.68473741.26903500h42m44.34s41d16m08.53s0.080.078700424433+41160859.4530.0510.0525385.68.6680.0500.0515089.98.4750.0500.0513684.8EEE22211100055665520n1997-10-248121.174-21.573000.169298237.8886720.78500.19300.97800
+
+
diff --git a/astroquery/lcogt/tests/data/Cone_coord.xml b/astroquery/lcogt/tests/data/Cone_coord.xml new file mode 100644 index 0000000000..97a1c67d8e --- /dev/null +++ b/astroquery/lcogt/tests/data/Cone_coord.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
10.68473741.26903500h42m44.34s41d16m08.53s0.080.078700424433+41160859.4530.0510.0525385.68.6680.0500.0515089.98.4750.0500.0513684.8EEE22211100055665520n1997-10-248121.174-21.573000.12843098.0560100.78500.19300.97800
+
+
diff --git a/astroquery/lcogt/tests/data/Polygon.xml b/astroquery/lcogt/tests/data/Polygon.xml new file mode 100644 index 0000000000..3c0f7cfedd --- /dev/null +++ b/astroquery/lcogt/tests/data/Polygon.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
10.01569610.09922800h40m03.77s10d05m57.22s0.100.079000400376+100557215.2370.0520.05428.014.6350.0660.06722.414.4810.0940.09514.6AAA22211100066350500n2000-09-2164118.312-52.670U0.225019.2017.2010.60200.15400.75600
10.03101610.06308200h40m07.44s10d03m47.10s0.190.1811400400744+100347016.4120.1170.1179.515.6030.1100.1109.215.3120.1580.1586.8BBC22211100006060600n2000-09-2164118.332-52.707U0.67319.9018.6010.80900.29101.10001
10.03677610.06027800h40m08.83s10d03m37.00s0.110.069000400882+100337015.3540.0450.04625.214.8860.0730.07317.814.5140.0890.08914.2AAA22211100066260600n2000-09-2164118.341-52.711U0.55018.4017.0010.46800.37200.84002
10.05996410.08544500h40m14.39s10d05m07.60s0.230.209600401439+100507616.3400.1030.10410.215.6430.1310.1318.815.3700.1730.1736.4ABC22211100016060500n2000-09-2164118.382-52.687U0.69819.4018.5010.69700.27300.97003
10.01583910.03806100h40m03.80s10d02m17.02s0.090.069000400380+100217014.6620.0260.02947.614.1100.0390.04036.313.7970.0500.05127.4AAA22211100066666600n2000-09-2164118.305-52.731000.55200.31300.86504
10.01117010.09390300h40m02.68s10d05m38.05s0.230.2116700400268+100538016.3730.1260.1279.815.9950.1690.1696.415.3930.1790.1796.3BCC22211100006060500n2000-09-2164118.304-52.675U2.411119.7018.5010.37800.60200.98005
10.00554910.01840100h40m01.33s10d01m06.24s0.160.1410800400133+100106216.1730.0970.09811.815.5110.1350.13510.014.9450.1120.1139.5ABB22211100016160600n2000-09-2164118.286-52.750000.66200.56601.22806
+
+
diff --git a/astroquery/lcogt/tests/setup_package.py b/astroquery/lcogt/tests/setup_package.py new file mode 100644 index 0000000000..a8ab506530 --- /dev/null +++ b/astroquery/lcogt/tests/setup_package.py @@ -0,0 +1,8 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +import os + + +def get_package_data(): + paths = [os.path.join('data', '*.xml'), + ] + return {'astroquery.lcogt.tests': paths} diff --git a/astroquery/lcogt/tests/test_lcogt.py b/astroquery/lcogt/tests/test_lcogt.py new file mode 100644 index 0000000000..50aca01823 --- /dev/null +++ b/astroquery/lcogt/tests/test_lcogt.py @@ -0,0 +1,159 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +from __future__ import print_function +import os +import re +import requests +import numpy as np + +from astropy.tests.helper import pytest +from astropy.table import Table +import astropy.coordinates as coord +import astropy.units as u + +from ...utils.testing_tools import MockResponse +from ...utils import commons +from ... import lcogt +from ...lcogt import conf + +DATA_FILES = {'Cone': 'Cone.xml', + 'Box': 'Box.xml', + 'Polygon': 'Polygon.xml'} + +OBJ_LIST = ["m31", "00h42m44.330s +41d16m07.50s", + commons.GalacticCoordGenerator(l=121.1743, b=-21.5733, unit=(u.deg, + u.deg))] + + +def data_path(filename): + data_dir = os.path.join(os.path.dirname(__file__), 'data') + return os.path.join(data_dir, filename) + + +@pytest.fixture +def patch_get(request): + mp = request.getfuncargvalue("monkeypatch") + mp.setattr(lcogt.core.Lcogt, '_request', get_mockreturn) + return mp + + +def get_mockreturn(method, url, params=None, timeout=10, cache=True, **kwargs): + filename = data_path(DATA_FILES[params['spatial']]) + content = open(filename, 'rb').read() + return MockResponse(content, **kwargs) + + +@pytest.mark.parametrize(('dim'), ['5d0m0s', 0.3 * u.rad, '5h0m0s', 2 * u.arcmin]) +def test_parse_dimension(dim): + # check that the returned dimension is always in units of 'arcsec', 'arcmin' or 'deg' + new_dim = lcogt.core._parse_dimension(dim) + assert new_dim.unit in ['arcsec', 'arcmin', 'deg'] + + +@pytest.mark.parametrize(('ra', 'dec', 'expected'), + [(10, 10, '10 +10'), + (10.0, -11, '10.0 -11') + ]) +def test_format_decimal_coords(ra, dec, expected): + out = lcogt.core._format_decimal_coords(ra, dec) + assert out == expected + + +@pytest.mark.parametrize(('coordinates', 'expected'), + [("5h0m0s 0d0m0s", "75.0 +0.0") + ]) +def test_parse_coordinates(coordinates, expected): + out = lcogt.core._parse_coordinates(coordinates) + for a, b in zip(out.split(), expected.split()): + try: + a = float(a) + b = float(b) + np.testing.assert_almost_equal(a, b) + except ValueError: + assert a == b + + +def test_args_to_payload(): + out = lcogt.core.Lcogt._args_to_payload("lco_img") + assert out == dict(catalog='lco_img', outfmt=3, outrows=conf.row_limit, spatial=None) + +@pytest.mark.parametrize(("coordinates"), OBJ_LIST) +def test_query_region_cone_async(coordinates, patch_get): + response = lcogt.core.Lcogt.query_region_async(coordinates, catalog='lco_img', spatial='Cone', + radius=2 * u.arcmin, get_query_payload=True) + assert response['radius'] == 2 + assert response['radunits'] == 'arcmin' + response = lcogt.core.Lcogt.query_region_async(coordinates, catalog='lco_img', spatial='Cone', + radius=2 * u.arcmin) + assert response is not None + + +@pytest.mark.parametrize(("coordinates"), OBJ_LIST) +def test_query_region_cone(coordinates, patch_get): + result = lcogt.core.Lcogt.query_region(coordinates, catalog='lco_img', spatial='Cone', + radius=2 * u.arcmin) + assert isinstance(result, Table) + + +@pytest.mark.parametrize(("coordinates"), OBJ_LIST) +def test_query_region_box_async(coordinates, patch_get): + response = lcogt.core.Lcogt.query_region_async(coordinates, catalog='lco_img', spatial='Box', + width=2 * u.arcmin, get_query_payload=True) + assert response['size'] == 120 + response = lcogt.core.Lcogt.query_region_async(coordinates, catalog='lco_img', spatial='Box', + width=2 * u.arcmin) + assert response is not None + + +@pytest.mark.parametrize(("coordinates"), OBJ_LIST) +def test_query_region_box(coordinates, patch_get): + result = lcogt.core.Lcogt.query_region(coordinates, catalog='lco_img', spatial='Box', + width=2 * u.arcmin) + assert isinstance(result, Table) + +poly1 = [coord.ICRS(ra=10.1, dec=10.1, unit=(u.deg, u.deg)), + coord.ICRS(ra=10.0, dec=10.1, unit=(u.deg, u.deg)), + coord.ICRS(ra=10.0, dec=10.0, unit=(u.deg, u.deg))] +poly2 = [(10.1 * u.deg, 10.1 * u.deg), (10.0 * u.deg, 10.1 * u.deg), (10.0 * u.deg, 10.0 * u.deg)] + + +@pytest.mark.parametrize(("polygon"), + [poly1, + poly2 + ]) +def test_query_region_async_polygon(polygon, patch_get): + response = lcogt.core.Lcogt.query_region_async("m31", catalog="lco_img", spatial="Polygon", + polygon=polygon, get_query_payload=True) + + for a, b in zip(re.split("[ ,]", response["polygon"]), + re.split("[ ,]", "10.1 +10.1,10.0 +10.1,10.0 +10.0")): + for a1, b1 in zip(a.split(), b.split()): + a1 = float(a1) + b1 = float(b1) + np.testing.assert_almost_equal(a1, b1) + + response = lcogt.core.Lcogt.query_region_async("m31", catalog="lco_img", spatial="Polygon", + polygon=polygon) + assert response is not None + + +@pytest.mark.parametrize(("polygon"), + [poly1, + poly2, + ]) +def test_query_region_polygon(polygon, patch_get): + result = lcogt.core.Lcogt.query_region("m31", catalog="lco_img", spatial="Polygon", + polygon=polygon) + assert isinstance(result, Table) + + +@pytest.mark.parametrize(('spatial', 'result'), zip(('Cone', 'Box', 'Polygon', 'All-Sky'), ('Cone', 'Box', 'Polygon', 'NONE'))) +def test_spatial_valdi(spatial, result): + out = lcogt.core.Lcogt._parse_spatial(spatial, coordinates='m31', radius=5 * u.deg, width=5 * u.deg, polygon=[(5 * u.hour, 5 * u.deg)] * 3) + assert out['spatial'] == result + + +@pytest.mark.parametrize(('spatial'), [('cone', 'box', 'polygon', 'all-Sky', 'All-sky', 'invalid', 'blah')]) +def test_spatial_invalid(spatial): + with pytest.raises(ValueError): + lcogt.core.Lcogt._parse_spatial(spatial, coordinates='m31') + diff --git a/astroquery/lcogt/tests/test_lcogt_remote.py b/astroquery/lcogt/tests/test_lcogt_remote.py new file mode 100644 index 0000000000..bf90e7b708 --- /dev/null +++ b/astroquery/lcogt/tests/test_lcogt_remote.py @@ -0,0 +1,61 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +from __future__ import print_function + +from astropy.tests.helper import remote_data +from astropy.table import Table +import astropy.coordinates as coord +import astropy.units as u + +import requests +import imp +imp.reload(requests) + +from ... import lcogt + +OBJ_LIST = ["m31", "00h42m44.330s +41d16m07.50s", coord.Galactic(l=121.1743, b=-21.5733, unit=(u.deg, u.deg))] + + +@remote_data +class TestLcogt: + + def test_query_object_meta(self): + response = lcogt.core.Lcogt.query_object_async('M1', catalog='lco_img') + assert response is not None + + def test_query_object_phot(self): + response = lcogt.core.Lcogt.query_object_async('M1', catalog='lco_cat') + assert response is not None + + def test_query_region_cone_async(self): + response = lcogt.core.Lcogt.query_region_async('m31', catalog='lco_img', spatial='Cone', + radius=2 * u.arcmin) + assert response is not None + + def test_query_region_cone(self): + result = lcogt.core.Lcogt.query_region('m31', catalog='lco_img', spatial='Cone', + radius=2 * u.arcmin) + assert isinstance(result, Table) + + def test_query_region_box_async(self): + response = lcogt.core.Lcogt.query_region_async("00h42m44.330s +41d16m07.50s", catalog='lco_img', spatial='Box', + width=2 * u.arcmin) + assert response is not None + + def test_query_region_box(self): + result = lcogt.core.Lcogt.query_region("00h42m44.330s +41d16m07.50s", catalog='lco_img', spatial='Box', + width=2 * u.arcmin) + assert isinstance(result, Table) + + def test_query_region_async_polygon(self): + polygon = [coord.ICRS(ra=10.1, dec=10.1, unit=(u.deg, u.deg)), + coord.ICRS(ra=10.0, dec=10.1, unit=(u.deg, u.deg)), + coord.ICRS(ra=10.0, dec=10.0, unit=(u.deg, u.deg))] + response = lcogt.core.Lcogt.query_region_async("m31", catalog="lco_img", spatial="Polygon", + polygon=polygon) + assert response is not None + + def test_query_region_polygon(self): + polygon = [(10.1, 10.1), (10.0, 10.1), (10.0, 10.0)] + result = lcogt.core.Lcogt.query_region("m31", catalog="lco_img", spatial="Polygon", + polygon=polygon) + assert isinstance(result, Table)