Source code for astropy.coordinates.name_resolve
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
This module contains convenience functions for getting a coordinate object
for a named object by querying SESAME and getting the first returned result.
Note that this is intended to be a convenience, and is very simple. If you
need precise coordinates for an object you should find the appropriate
reference for that measurement and input the coordinates manually.
"""
from __future__ import (absolute_import, division, print_function,
unicode_literals)
# Standard library
import os
import re
import socket
# Astropy
from ..config import ConfigurationItem
from ..extern.six.moves import urllib
from .. import units as u
from .builtin_systems import ICRS
__all__ = ["get_icrs_coordinates"]
SESAME_URL = ConfigurationItem("sesame_url",
["http://cdsweb.u-strasbg.fr/cgi-bin/nph-sesame/",
"http://vizier.cfa.harvard.edu/viz-bin/nph-sesame/"],
"The URL to Sesame's web-queryable database.",
cfgtype='string_list')
SESAME_DATABASE = ConfigurationItem("sesame_database", ['all', 'simbad', 'ned',
'vizier'],
"This specifies the default database that "
"SESAME will query when using the name "
"resolve mechanism in the coordinates "
"subpackage. Default is to search all "
"databases, but this can be 'all', "
"'simbad', 'ned', or 'vizier'.")
NAME_RESOLVE_TIMEOUT = ConfigurationItem('name_resolve_timeout', 5,
"This is the maximum time to wait "
"for a response from a name resolve "
"query to SESAME in seconds.")
class NameResolveError(Exception):
pass
def _parse_response(resp_data):
"""
Given a string response from SESAME, parse out the coordinates by looking
for a line starting with a J, meaning ICRS J2000 coordinates.
Parameters
----------
resp_data : str
The string HTTP response from SESAME.
Returns
-------
ra : str
The string Right Ascension parsed from the HTTP response.
dec : str
The string Declination parsed from the HTTP response.
"""
pattr = re.compile(r"%J\s*([0-9\.]+)\s*([\+\-\.0-9]+)")
matched = pattr.search(resp_data.decode('utf-8'))
if matched == None:
return None, None
else:
ra,dec = matched.groups()
return ra,dec
[docs]def get_icrs_coordinates(name):
"""
Retrieve an ICRS object by using an online name resolving
service to retrieve coordinates for the specified name. By default,
this will search all available databases until a match is found. If
you would like to specify the database, use the configuration item
`name_resolve.SESAME_DATABASE` . You can also specify a list of servers
to use for querying Sesame using the configuration item
`name_resolve.SESAME_URL`. This will try each one in order until a valid
response is returned. By default, this list includes the main Sesame
host and a mirror at vizier. A final configuration item,
`name_resolve.NAME_RESOLVE_TIMEOUT`, is the number of seconds to wait
for a response from the server before giving up. By default this is
5 seconds.
Parameters
----------
name : str
The name of the object to get coordinates for, e.g. M42.
Returns
-------
coord : SphericalCoordinatesBase
An `ICRS` instance for the object name specified.
"""
database = SESAME_DATABASE()
# The web API just takes the first letter of the database name
db = database.upper()[0]
# Make sure we don't have duplicates in the url list
urls = []
domains = []
for url in SESAME_URL():
domain = urllib.parse.urlparse(url).netloc
# Check for duplicates
if domain not in domains:
domains.append(domain)
# Add the query to the end of the url, add to url list
fmt_url = os.path.join(url, "{db}?{name}")
fmt_url = fmt_url.format(name=urllib.parse.quote(name), db=db)
urls.append(fmt_url)
for url in urls:
try:
# Retrieve ascii name resolve data from CDS
resp = urllib.request.urlopen(url, timeout=NAME_RESOLVE_TIMEOUT())
break
except urllib.error.URLError as e:
# This catches a timeout error, see:
# http://stackoverflow.com/questions/2712524/handling-urllib2s-timeout-python
if isinstance(e.reason, socket.timeout):
# If it was a timeout, try with the next URL
continue
else:
raise NameResolveError("Unable to retrieve coordinates for name "
"'{0}'".format(name))
# All Sesame URL's timed out...
else:
raise NameResolveError("All Sesame queries timed out. Unable to "
"retrieve coordinates.")
resp_data = resp.read()
ra,dec = _parse_response(resp_data)
if ra == None and dec == None:
if db == "A":
err = "Unable to find coordinates for name '{0}'".format(name)
else:
err = "Unable to find coordinates for name '{0}' in database {1}"\
.format(name, database)
raise NameResolveError(err)
return ICRS(ra, dec, unit=(u.degree, u.degree))