files: # Licensed under a 3-clause BSD style license - see LICENSE.rst
  
  # 1. standard library imports
  from io import BytesIO
  import os
  from urllib.parse import unquote, urlparse
  import time
  from xml.etree import ElementTree
  from datetime import datetime, timezone
  
  # 2. third party imports
  import astropy.units as u
  import astropy.coordinates as coord
  from astropy.table import Table
  from astropy.io.votable import parse
  from astroquery import log
  import numpy as np
  
  # 3. local imports - use relative imports
  # commonly required local imports shown below as example
  # all Query classes should inherit from BaseQuery.
  from ..query import BaseQuery
  # has common functions required by most modules
  from ..utils import commons
  # prepend_docstr is a way to copy docstrings between methods
  from ..utils import prepend_docstr_nosections
  # async_to_sync generates the relevant query tools from _async methods
  from ..utils import async_to_sync
  # import configurable items declared in __init__.py
  from . import conf
  
  # export all the public classes and methods
  __all__ = ['Casda', 'CasdaClass']
  
  
  @async_to_sync
  class CasdaClass(BaseQuery):
  
      """
      Class for accessing ASKAP data through the CSIRO ASKAP Science Data Archive (CASDA). Typical usage:
  
      result = Casda.query_region('22h15m38.2s -45d50m30.5s', radius=0.5 * u.deg)
      """
      # use the Configuration Items imported from __init__.py to set the URL,
      # TIMEOUT, etc.
      URL = conf.server
      TIMEOUT = conf.timeout
      POLL_INTERVAL = conf.poll_interval
      _soda_base_url = conf.soda_base_url
      _uws_ns = {'uws': 'http://www.ivoa.net/xml/UWS/v1.0'}
  
      def __init__(self, user=None, password=None):
          super(CasdaClass, self).__init__()
          if user is None:
              self._authenticated = False
          else:
              self._authenticated = True
              # self._user = user
              # self._password = password
              self._auth = (user, password)
  
      def query_region_async(self, coordinates, radius=1*u.arcmin, height=None, width=None,
                             get_query_payload=False, cache=True):
          """
          Queries a region around the specified coordinates. Either a radius or both a height and a width must be provided.
  
          Parameters
          ----------
          coordinates : str or `astropy.coordinates`.
              coordinates around which to query
          radius : str or `astropy.units.Quantity`, optional
              the radius of the cone search
          height : str or `astropy.units.Quantity`, optional
              the height for a box region
          width : str or `astropy.units.Quantity`, optional
              the width for a box region
          get_query_payload : bool, optional
              Just return the dict of HTTP request parameters.
          cache: bool, optional
              Use the astroquery internal query result cache
  
          Returns
          -------
          response : `requests.Response`
              The HTTP response returned from the service.
              All async methods should return the raw HTTP response.
          """
          request_payload = self._args_to_payload(coordinates=coordinates, radius=radius, height=height,
                                                  width=width)
          if get_query_payload:
              return request_payload
  
          response = self._request('GET', self.URL, params=request_payload,
                                   timeout=self.TIMEOUT, cache=cache)
  
          # result = self._parse_result(response)
          return response
  
      # Create the dict of HTTP request parameters by parsing the user
      # entered values.
      def _args_to_payload(self, radius=1*u.arcmin, **kwargs):
          request_payload = dict()
  
          # Convert the coordinates to FK5
          coordinates = kwargs.get('coordinates')
          if coordinates is not None:
              fk5_coords = commons.parse_coordinates(coordinates).transform_to(coord.FK5)
  
              if kwargs.get('width') is not None and kwargs.get('height') is not None:
                  width = u.Quantity(kwargs['width']).to(u.deg).value
                  height = u.Quantity(kwargs['height']).to(u.deg).value
                  top = fk5_coords.dec.degree + (height/2)
                  bottom = fk5_coords.dec.degree - (height/2)
                  left = fk5_coords.ra.degree - (width/2)
                  right = fk5_coords.ra.degree + (width/2)
                  pos = f'RANGE {left} {right} {bottom} {top}'
              else:
                  radius = u.Quantity(radius).to(u.deg)
                  pos = f'CIRCLE {fk5_coords.ra.degree} {fk5_coords.dec.degree} {radius.value}'
  
              request_payload['POS'] = pos
  
          band = kwargs.get('band')
          channel = kwargs.get('channel')
          if band is not None:
              if channel is not None:
                  raise ValueError("Either 'channel' or 'band' values may be provided but not both.")
  
              if (not isinstance(band, (list, tuple, np.ndarray))) or len(band) != 2 or \
                      (band[0] is not None and not isinstance(band[0], u.Quantity)) or \
                      (band[1] is not None and not isinstance(band[1], u.Quantity)):
                  raise ValueError("The 'band' value must be a list of 2 wavelength or frequency values.")
  
              bandBoundedLow = band[0] is not None
              bandBoundedHigh = band[1] is not None
              if bandBoundedLow and bandBoundedHigh and band[0].unit.physical_type != band[1].unit.physical_type:
                  raise ValueError("The '
  
  [... the rest is omitted ...]
files: astroquery/casda/core.py
files: # Licensed under a 3-clause BSD style license - see LICENSE.rst
  
  # 1. standard library imports
  from io import BytesIO
  import os
  from urllib.parse import unquote, urlparse
  import time
  from xml.etree import ElementTree
  from datetime import datetime, timezone
  
  # 2. third party imports
  import astropy.units as u
  import astropy.coordinates as coord
  from astropy.table import Table
  from astropy.io.votable import parse
  from astroquery import log
  
  # 3. local imports - use relative imports
  # commonly required local imports shown below as example
  # all Query classes should inherit from BaseQuery.
  from ..query import BaseQuery
  # has common functions required by most modules
  from ..utils import commons
  # prepend_docstr is a way to copy docstrings between methods
  from ..utils import prepend_docstr_nosections
  # async_to_sync generates the relevant query tools from _async methods
  from ..utils import async_to_sync
  # import configurable items declared in __init__.py
  from . import conf
  
  # export all the public classes and methods
  __all__ = ['Casda', 'CasdaClass']
  
  
  @async_to_sync
  class CasdaClass(BaseQuery):
  
      """
      Class for accessing ASKAP data through the CSIRO ASKAP Science Data Archive (CASDA). Typical usage:
  
      result = Casda.query_region('22h15m38.2s -45d50m30.5s', radius=0.5 * u.deg)
      """
      # use the Configuration Items imported from __init__.py to set the URL,
      # TIMEOUT, etc.
      URL = conf.server
      TIMEOUT = conf.timeout
      POLL_INTERVAL = conf.poll_interval
      _soda_base_url = conf.soda_base_url
      _uws_ns = {'uws': 'http://www.ivoa.net/xml/UWS/v1.0'}
  
      def __init__(self, user=None, password=None):
          super(CasdaClass, self).__init__()
          if user is None:
              self._authenticated = False
          else:
              self._authenticated = True
              # self._user = user
              # self._password = password
              self._auth = (user, password)
  
      def query_region_async(self, coordinates, radius=1*u.arcmin, height=None, width=None,
                             get_query_payload=False, cache=True):
          """
          Queries a region around the specified coordinates. Either a radius or both a height and a width must be provided.
  
          Parameters
          ----------
          coordinates : str or `astropy.coordinates`.
              coordinates around which to query
          radius : str or `astropy.units.Quantity`, optional
              the radius of the cone search
          height : str or `astropy.units.Quantity`, optional
              the height for a box region
          width : str or `astropy.units.Quantity`, optional
              the width for a box region
          get_query_payload : bool, optional
              Just return the dict of HTTP request parameters.
          cache: bool, optional
              Use the astroquery internal query result cache
  
          Returns
          -------
          response : `requests.Response`
              The HTTP response returned from the service.
              All async methods should return the raw HTTP response.
          """
          request_payload = self._args_to_payload(coordinates=coordinates, radius=radius, height=height,
                                                  width=width)
          if get_query_payload:
              return request_payload
  
          response = self._request('GET', self.URL, params=request_payload,
                                   timeout=self.TIMEOUT, cache=cache)
  
          # result = self._parse_result(response)
          return response
  
      # Create the dict of HTTP request parameters by parsing the user
      # entered values.
      def _args_to_payload(self, radius=1*u.arcmin, **kwargs):
          request_payload = dict()
  
          # Convert the coordinates to FK5
          coordinates = kwargs.get('coordinates')
          if coordinates is not None:
              fk5_coords = commons.parse_coordinates(coordinates).transform_to(coord.FK5)
  
              if kwargs.get('width') is not None and kwargs.get('height') is not None:
                  width = u.Quantity(kwargs['width']).to(u.deg).value
                  height = u.Quantity(kwargs['height']).to(u.deg).value
                  top = fk5_coords.dec.degree + (height/2)
                  bottom = fk5_coords.dec.degree - (height/2)
                  left = fk5_coords.ra.degree - (width/2)
                  right = fk5_coords.ra.degree + (width/2)
                  pos = f'RANGE {left} {right} {bottom} {top}'
              else:
                  radius = u.Quantity(radius).to(u.deg)
                  pos = f'CIRCLE {fk5_coords.ra.degree} {fk5_coords.dec.degree} {radius.value}'
  
              request_payload['POS'] = pos
  
          band = kwargs.get('band')
          channel = kwargs.get('channel')
          if band is not None:
              if channel is not None:
                  raise ValueError("Either 'channel' or 'band' values may be provided but not both.")
  
              if (not isinstance(band, (list, tuple))) or len(band) != 2 or \
                      (band[0] is not None and not isinstance(band[0], u.Quantity)) or \
                      (band[1] is not None and not isinstance(band[1], u.Quantity)):
                  raise ValueError("The 'band' value must be a list of 2 wavelength or frequency values.")
  
              bandBoundedLow = band[0] is not None
              bandBoundedHigh = band[1] is not None
              if bandBoundedLow and bandBoundedHigh and band[0].unit.physical_type != band[1].unit.physical_type:
                  raise ValueError("The 'band' values must have the same kind of
  
  [... the rest is omitted ...]
files: astroquery/casda/core.py
files: # -*- coding: utf-8 -*
  
  # Licensed under a 3-clause BSD style license - see LICENSE.rst
  
  
  import pytest
  import requests
  import os
  
  from astropy.coordinates import SkyCoord
  import astropy.units as u
  from astropy.table import Table, Column
  from astropy.io.votable import parse
  from astroquery import log
  import numpy as np
  
  from astroquery.casda import Casda
  
  try:
      from unittest.mock import Mock, patch, MagicMock
  except ImportError:
      pytest.skip("Install mock for the casda tests.", allow_module_level=True)
  
  DATA_FILES = {'CIRCLE': 'cone.xml', 'RANGE': 'box.xml', 'DATALINK': 'datalink.xml', 'RUN_JOB': 'run_job.xml',
                'COMPLETED_JOB': 'completed_job.xml', 'DATALINK_NOACCESS': 'datalink_noaccess.xml',
                'cutout_CIRCLE_333.9092_-45.8418_0.5000': 'cutout_333.9092_-45.8418_0.5000.xml'}
  
  
  class MockResponse:
  
      def __init__(self, content):
          self.content = content
          self.text = content.decode()
  
      def raise_for_status(self):
          return
  
  
  def get_mockreturn(self, method, url, data=None, timeout=10,
                     files=None, params=None, headers=None, **kwargs):
      log.debug("get_mockreturn url:{} params:{} kwargs:{}".format(url, params, kwargs))
      if kwargs and 'auth' in kwargs:
          auth = kwargs['auth']
          if auth and (auth[0] != 'user' or auth[1] != 'password'):
              log.debug("Rejecting credentials")
              return create_auth_failure_response()
  
      if 'data/async' in str(url):
          # Responses for an asynchronous SODA job
          if str(url).endswith('data/async'):
              self.first_job_pass = True
              self.completed_job_key = "COMPLETED_JOB"
              return create_soda_create_response('111-000-111-000')
          elif str(url).endswith('/phase') and method == 'POST':
              key = "RUN_JOB"
          elif str(url).endswith('111-000-111-000/parameters') and method == 'POST':
              assert "POS" in data
              print(data['POS'])
              pos_parts = data['POS'].split(' ')
              assert len(pos_parts) == 4
              self.completed_job_key = 'cutout_{}_{:.4f}_{:.4f}_{:.4f}'.format(pos_parts[0], float(pos_parts[1]),
                  float(pos_parts[2]), float(pos_parts[3]))
              return create_soda_create_response('111-000-111-000')
          elif str(url).endswith('111-000-111-000') and method == 'GET':
              key = "RUN_JOB" if self.first_job_pass else self.completed_job_key
              self.first_job_pass = False
          else:
              raise ValueError("Unexpected SODA async {} call to url {}".format(method, url))
      elif 'datalink' in str(url):
          if 'cube-244' in str(url):
              key = 'DATALINK'
          else:
              key = 'DATALINK_NOACCESS'
      else:
          key = params['POS'].split()[0] if params['POS'] else None
      filename = data_path(DATA_FILES[key])
      log.debug('providing ' + filename)
      content = open(filename, 'rb').read()
      return MockResponse(content)
  
  
  def create_soda_create_response(jobid):
      job_url = 'https://casda.csiro.au/casda_data_access/data/async/' + jobid
      create_response_headers = [
          ['location', job_url]
      ]
  
      create_response = Mock(spec=requests.Response)
      create_response.configure_mock(status_code=303, message='OK', headers=create_response_headers, url=job_url)
      return create_response
  
  
  def create_auth_failure_response():
      unauthenticated_headers = [
          ['WWW-Authenticate', 'Basic realm="ATNF OPAL Login"']
      ]
      create_response = MagicMock(spec=requests.Response)
      attrs = {'raise_for_status.side_effect': requests.exceptions.HTTPError()}
      create_response.configure_mock(status_code=401, message='OK', headers=unauthenticated_headers, **attrs)
      return create_response
  
  
  @pytest.fixture
  def patch_get(request):
      mp = request.getfixturevalue("monkeypatch")
  
      mp.setattr(requests.Session, 'request', get_mockreturn)
      return mp
  
  
  def data_path(filename):
      data_dir = os.path.join(os.path.dirname(__file__), 'data')
      return os.path.join(data_dir, filename)
  
  
  def isclose(value1, value2, abs_tol=1e-09):
      return abs(value1 - value2) < abs_tol
  
  
  def test_query_region_text_radius(patch_get):
      ra = 333.9092
      dec = -45.8418
      radius = 0.5
      query_payload = Casda.query_region('22h15m38.2s -45d50m30.5s', radius=radius * u.deg, cache=False,
                                         get_query_payload=True)
      assert isinstance(query_payload, dict)
      assert 'POS' in query_payload
      assert query_payload['POS'].startswith('CIRCLE 333')
      pos_parts = query_payload['POS'].split(' ')
      assert pos_parts[0] == 'CIRCLE'
      assert isclose(float(pos_parts[1]), ra, abs_tol=1e-4)
      assert isclose(float(pos_parts[2]), dec, abs_tol=1e-4)
      assert isclose(float(pos_parts[3]), radius)
      assert len(pos_parts) == 4
  
      responses = Casda.query
  
  [... the rest is omitted ...]
files: astroquery/casda/tests/test_casda.py
files: # -*- coding: utf-8 -*
  
  # Licensed under a 3-clause BSD style license - see LICENSE.rst
  
  
  import pytest
  import requests
  import os
  
  from astropy.coordinates import SkyCoord
  import astropy.units as u
  from astropy.table import Table, Column
  from astropy.io.votable import parse
  from astroquery import log
  
  from astroquery.casda import Casda
  
  try:
      from unittest.mock import Mock, patch, MagicMock
  except ImportError:
      pytest.skip("Install mock for the casda tests.", allow_module_level=True)
  
  DATA_FILES = {'CIRCLE': 'cone.xml', 'RANGE': 'box.xml', 'DATALINK': 'datalink.xml', 'RUN_JOB': 'run_job.xml',
                'COMPLETED_JOB': 'completed_job.xml', 'DATALINK_NOACCESS': 'datalink_noaccess.xml',
                'cutout_CIRCLE_333.9092_-45.8418_0.5000': 'cutout_333.9092_-45.8418_0.5000.xml'}
  
  
  class MockResponse:
  
      def __init__(self, content):
          self.content = content
          self.text = content.decode()
  
      def raise_for_status(self):
          return
  
  
  def get_mockreturn(self, method, url, data=None, timeout=10,
                     files=None, params=None, headers=None, **kwargs):
      log.debug("get_mockreturn url:{} params:{} kwargs:{}".format(url, params, kwargs))
      if kwargs and 'auth' in kwargs:
          auth = kwargs['auth']
          if auth and (auth[0] != 'user' or auth[1] != 'password'):
              log.debug("Rejecting credentials")
              return create_auth_failure_response()
  
      if 'data/async' in str(url):
          # Responses for an asynchronous SODA job
          if str(url).endswith('data/async'):
              self.first_job_pass = True
              self.completed_job_key = "COMPLETED_JOB"
              return create_soda_create_response('111-000-111-000')
          elif str(url).endswith('/phase') and method == 'POST':
              key = "RUN_JOB"
          elif str(url).endswith('111-000-111-000/parameters') and method == 'POST':
              assert "POS" in data
              print(data['POS'])
              pos_parts = data['POS'].split(' ')
              assert len(pos_parts) == 4
              self.completed_job_key = 'cutout_{}_{:.4f}_{:.4f}_{:.4f}'.format(pos_parts[0], float(pos_parts[1]),
                  float(pos_parts[2]), float(pos_parts[3]))
              return create_soda_create_response('111-000-111-000')
          elif str(url).endswith('111-000-111-000') and method == 'GET':
              key = "RUN_JOB" if self.first_job_pass else self.completed_job_key
              self.first_job_pass = False
          else:
              raise ValueError("Unexpected SODA async {} call to url {}".format(method, url))
      elif 'datalink' in str(url):
          if 'cube-244' in str(url):
              key = 'DATALINK'
          else:
              key = 'DATALINK_NOACCESS'
      else:
          key = params['POS'].split()[0] if params['POS'] else None
      filename = data_path(DATA_FILES[key])
      log.debug('providing ' + filename)
      content = open(filename, 'rb').read()
      return MockResponse(content)
  
  
  def create_soda_create_response(jobid):
      job_url = 'https://casda.csiro.au/casda_data_access/data/async/' + jobid
      create_response_headers = [
          ['location', job_url]
      ]
  
      create_response = Mock(spec=requests.Response)
      create_response.configure_mock(status_code=303, message='OK', headers=create_response_headers, url=job_url)
      return create_response
  
  
  def create_auth_failure_response():
      unauthenticated_headers = [
          ['WWW-Authenticate', 'Basic realm="ATNF OPAL Login"']
      ]
      create_response = MagicMock(spec=requests.Response)
      attrs = {'raise_for_status.side_effect': requests.exceptions.HTTPError()}
      create_response.configure_mock(status_code=401, message='OK', headers=unauthenticated_headers, **attrs)
      return create_response
  
  
  @pytest.fixture
  def patch_get(request):
      mp = request.getfixturevalue("monkeypatch")
  
      mp.setattr(requests.Session, 'request', get_mockreturn)
      return mp
  
  
  def data_path(filename):
      data_dir = os.path.join(os.path.dirname(__file__), 'data')
      return os.path.join(data_dir, filename)
  
  
  def isclose(value1, value2, abs_tol=1e-09):
      return abs(value1 - value2) < abs_tol
  
  
  def test_query_region_text_radius(patch_get):
      ra = 333.9092
      dec = -45.8418
      radius = 0.5
      query_payload = Casda.query_region('22h15m38.2s -45d50m30.5s', radius=radius * u.deg, cache=False,
                                         get_query_payload=True)
      assert isinstance(query_payload, dict)
      assert 'POS' in query_payload
      assert query_payload['POS'].startswith('CIRCLE 333')
      pos_parts = query_payload['POS'].split(' ')
      assert pos_parts[0] == 'CIRCLE'
      assert isclose(float(pos_parts[1]), ra, abs_tol=1e-4)
      assert isclose(float(pos_parts[2]), dec, abs_tol=1e-4)
      assert isclose(float(pos_parts[3]), radius)
      assert len(pos_parts) == 4
  
      responses = Casda.query_region('22h
  
  [... the rest is omitted ...]
files: astroquery/casda/tests/test_casda.py
files: .. _astroquery.casda:
  
  **********************************
  CASDA Queries (`astroquery.casda`)
  **********************************
  
  The CSIRO ASKAP Science Data Archive (CASDA) provides access to science-ready data products
  from observations at the `Australian Square Kilometre Array Pathfinder (ASKAP) <https://www.atnf.csiro.au/projects/askap/index.html>`_ telescope.
  These data products include source catalogues, images, spectral line and polarisation cubes, spectra and visbilities.
  This package allows querying of the data products available in CASDA (`<https://casda.csiro.au/>`_).
  
  Listing Data Products
  =====================
  
  The metadata for data products held in CASDA may be queried using the :meth:`~astroquery.casda.CasdaClass.query_region` method.
  The results are returned in a `~astropy.table.Table`.
  The method takes a location and either a radius or a height and width of the region to be queried.
  The location should be specified in ICRS coordinates or an `astropy.coordinates.SkyCoord` object.
  For example:
  
  .. doctest-remote-data::
  
      >>> from astroquery.casda import Casda
      >>> from astropy.coordinates import SkyCoord
      >>> from astropy import units as u
      >>> centre = SkyCoord.from_name('NGC 7232')
      >>> result_table = Casda.query_region(centre, radius=30*u.arcmin)
      >>> print(result_table['obs_publisher_did','s_ra', 's_dec', 'obs_release_date'][:5])
      obs_publisher_did       s_ra           s_dec           obs_release_date
                              deg             deg
      ----------------- --------------- ---------------- ------------------------
             cube-11460 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11461 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11462 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11463 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11464 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
  
  
  In most cases only public data is required. While most ASKAP data is public, some data products may not be released for quality reasons.
  Some derived data produced by science teams may also be embargoed to the science team for a period of team.
  To filter down to just the public data you can use the :meth:`~astroquery.casda.CasdaClass.filter_out_unreleased` method.
  
  For example to filter out the 30 non-public results from the above data set:
  
  .. doctest-remote-data::
  
      >>> public_results = Casda.filter_out_unreleased(result_table)
      >>> print(public_results['obs_publisher_did','s_ra', 's_dec', 'obs_release_date'][:5])
      obs_publisher_did       s_ra           s_dec           obs_release_date
                              deg             deg
      ----------------- --------------- ---------------- ------------------------
             cube-11460 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11461 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11462 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11463 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11464 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
  
  
  Authentication
  ==============
  
  User authentication is required to access data files from CASDA, including
  calibrated visibilities, images and image cubes.
  Authentication is made with OPAL credentials.
  To register with OPAL, go to https://opal.atnf.csiro.au/ and click on the
  link to 'Register'. Enter your email address, name, affiliation and a password.
  The OPAL application will register you straight away.
  
  OPAL user accounts are self-managed. Please keep your account details up to
  date. To change user-registration details, or to request a new OPAL password,
  use the link to 'Log in or reset password'.
  
  To use download tasks, you should create an instance of the ``Casda`` class
  with a username and password. e.g.:
  
  .. doctest-skip::
  
      >>> from astroquery.casda import Casda
      >>> import getpass
      >>> username = 'email@somewhere.edu.au'
      >>> password = getpass.getpass(str("Enter your OPAL password: "))
      >>> casda = Casda(username, password)
  
  
  Data Access
  ===========
  
  In order to access data in CASDA you must first stage the data using the :meth:`~astroquery.casda.CasdaClass.stage_data` 
  method.
  This is because only some of the data in CASDA is held on disc at any particular time.
  The :meth:`~astroquery.casda.CasdaClass.stage_data` method should be passed an astropy Table object containing an 
  'access_url' column.
  This column should contain the datalink address of the data product.
  
  Once the data has been assembled you can then download the data using the :meth:`~astroquery.casda.CasdaClass.download_files` 
  method, or using tools such as wget.
  Authentication is required when staging the data, but not for the download.
  
  An example script to download public continuum images of the NGC 7232 region
  t
  
  [... the rest is omitted ...]
files: docs/casda/casda.rst
files: .. _astroquery.casda:
  
  **********************************
  CASDA Queries (`astroquery.casda`)
  **********************************
  
  The CSIRO ASKAP Science Data Archive (CASDA) provides access to science-ready data products
  from observations at the `Australian Square Kilometre Array Pathfinder (ASKAP) <https://www.atnf.csiro.au/projects/askap/index.html>`_ telescope.
  These data products include source catalogues, images, spectral line and polarisation cubes, spectra and visbilities.
  This package allows querying of the data products available in CASDA (`<https://casda.csiro.au/>`_).
  
  Listing Data Products
  =====================
  
  The metadata for data products held in CASDA may be queried using the :meth:`~astroquery.casda.CasdaClass.query_region` method.
  The results are returned in a `~astropy.table.Table`.
  The method takes a location and either a radius or a height and width of the region to be queried.
  The location should be specified in ICRS coordinates or an `astropy.coordinates.SkyCoord` object.
  For example:
  
  .. doctest-remote-data::
  
      >>> from astroquery.casda import Casda
      >>> from astropy.coordinates import SkyCoord
      >>> from astropy import units as u
      >>> centre = SkyCoord.from_name('NGC 7232')
      >>> result_table = Casda.query_region(centre, radius=30*u.arcmin)
      >>> print(result_table['obs_publisher_did','s_ra', 's_dec', 'obs_release_date'][:5])
      obs_publisher_did       s_ra           s_dec           obs_release_date
                              deg             deg
      ----------------- --------------- ---------------- ------------------------
             cube-11460 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11461 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11462 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11463 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11464 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
  
  
  In most cases only public data is required. While most ASKAP data is public, some data products may not be released for quality reasons.
  Some derived data produced by science teams may also be embargoed to the science team for a period of team.
  To filter down to just the public data you can use the :meth:`~astroquery.casda.CasdaClass.filter_out_unreleased` method.
  
  For example to filter out the 30 non-public results from the above data set:
  
  .. doctest-remote-data::
  
      >>> public_results = Casda.filter_out_unreleased(result_table)
      >>> print(public_results['obs_publisher_did','s_ra', 's_dec', 'obs_release_date'][:5])
      obs_publisher_did       s_ra           s_dec           obs_release_date
                              deg             deg
      ----------------- --------------- ---------------- ------------------------
             cube-11460 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11461 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11462 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11463 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
             cube-11464 326.52250211117 -43.891190432671 2020-11-18T09:49:27.134Z
  
  
  Authentication
  ==============
  
  User authentication is required to access data files from CASDA, including
  calibrated visibilities, images and image cubes.
  Authentication is made with OPAL credentials.
  To register with OPAL, go to https://opal.atnf.csiro.au/ and click on the
  link to 'Register'. Enter your email address, name, affiliation and a password.
  The OPAL application will register you straight away.
  
  OPAL user accounts are self-managed. Please keep your account details up to
  date. To change user-registration details, or to request a new OPAL password,
  use the link to 'Log in or reset password'.
  
  To use download tasks, you should create an instance of the ``Casda`` class
  with a username and password. e.g.:
  
  .. doctest-skip::
  
      >>> from astroquery.casda import Casda
      >>> import getpass
      >>> username = 'email@somewhere.edu.au'
      >>> password = getpass.getpass(str("Enter your OPAL password: "))
      >>> casda = Casda(username, password)
  
  
  Data Access
  ===========
  
  In order to access data in CASDA you must first stage the data using the :meth:`~astroquery.casda.CasdaClass.stage_data` 
  method.
  This is because only some of the data in CASDA is held on disc at any particular time.
  The :meth:`~astroquery.casda.CasdaClass.stage_data` method should be passed an astropy Table object containing an 
  'access_url' column.
  This column should contain the datalink address of the data product.
  
  Once the data has been assembled you can then download the data using the :meth:`~astroquery.casda.CasdaClass.download_files` 
  method, or using tools such as wget.
  Authentication is required when staging the data, but not for the download.
  
  An example script to download public continuum images of the NGC 7232 region
  t
  
  [... the rest is omitted ...]
files: docs/casda/casda.rst