Source code for astroquery.nist.core

# Licensed under a 3-clause BSD style license - see LICENSE.rst


import html
import re

import astropy.units as u
from astropy.table import Table

from ..query import BaseQuery
from ..utils import async_to_sync, prepend_docstr_nosections
from . import conf
from ..exceptions import TableParseError

__all__ = ['Nist', 'NistClass']


def _strip_blanks(table):
    """
    Remove blank lines from table (included for "human readability" but
    useless to us...
    returns a single string joined by \n newlines

    Parameters
    ----------
    table : str
       table to strip as a string

    Returns
    -------
    single string joined by newlines.
    """
    numbersletters = re.compile("[0-9A-Za-z]")
    if isinstance(table, str):
        table = table.split('\n')
    table = [line for line in table if numbersletters.search(line)]
    return "\n".join(table)


[docs] @async_to_sync class NistClass(BaseQuery): URL = conf.server TIMEOUT = conf.timeout unit_code = {'Angstrom': 0, 'nm': 1, 'um': 2} energy_level_code = {'cm-1': 0, 'invcm': 0, 'cm': 0, 'ev': 1, 'eV': 1, 'EV': 1, 'electronvolt': 1, 'R': 2, 'Rydberg': 2, 'rydberg': 2} order_out_code = {'wavelength': 0, 'multiplet': 1} wavelength_unit_code = {'vacuum': 3, 'vac+air': 4} def _args_to_payload(self, *args, **kwargs): """ Serves the same purpose as `~NistClass.query` but returns the raw HTTP response rather than a `~astropy.table.Table` object. Parameters ---------- minwav : `astropy.units.Quantity` object The lower wavelength for the spectrum in appropriate units. maxwav : `astropy.units.Quantity` object The upper wavelength for the spectrum in appropriate units. linename : str or iterable of str, optional The spectrum/spectra to fetch. Defaults to "H I" energy_level_unit : str, optional The energy level units must be one of the following: 'R', 'Rydberg', 'rydberg', 'cm', 'cm-1', 'EV', 'eV', 'electronvolt', 'ev', 'invcm' Defaults to 'eV'. output_order : str, optional Decide ordering of output. Must be one of following: ['wavelength', 'multiplet']. Defaults to 'wavelength'. wavelength_type : str, optional Must be one of 'vacuum' or 'vac+air'. Defaults to 'vacuum'. get_query_payload : bool, optional If true then returns the dictionary of query parameters, posted to remote server. Defaults to `False`. Returns ------- request_payload : dict The dictionary of parameters sent with the HTTP request """ request_payload = {} linename = kwargs["linename"] request_payload["spectra"] = linename if isinstance(linename, str) else "; ".join(linename) (min_wav, max_wav, wav_unit) = _parse_wavelength(args[0], args[1]) request_payload["low_w"] = min_wav request_payload["upp_w"] = max_wav request_payload["unit"] = wav_unit request_payload["submit"] = "Retrieve Data" request_payload["format"] = 1 # ascii request_payload["line_out"] = 0 # All lines request_payload["en_unit"] = Nist.energy_level_code[ kwargs["energy_level_unit"]] request_payload["output_type"] = 0 # entirely rather than pagewise request_payload["bibrefs"] = 1 request_payload["show_obs_wl"] = 1 request_payload["show_calc_wl"] = 1 request_payload["order_out"] = Nist.order_out_code[ kwargs['output_order']] request_payload["max_low_enrg"] = "" request_payload["show_av"] = Nist.wavelength_unit_code[ kwargs['wavelength_type']] request_payload["max_upp_enrg"] = "" request_payload["tsb_value"] = 0 request_payload["min_str"] = "" request_payload["A_out"] = 0 request_payload["f_out"] = "on" request_payload["intens_out"] = "on" request_payload["max_str"] = "" request_payload["allowed_out"] = 1 request_payload["forbid_out"] = 1 request_payload["min_accur"] = "" request_payload["min_intens"] = "" request_payload["conf_out"] = "on" request_payload["term_out"] = "on" request_payload["enrg_out"] = "on" request_payload["J_out"] = "on" request_payload["g_out"] = "on" request_payload["page_size"] = 15 request_payload["remove_js"] = "on" request_payload["show_wn"] = 1 return request_payload
[docs] @prepend_docstr_nosections("\n" + _args_to_payload.__doc__) def query_async(self, minwav, maxwav, *, linename="H I", energy_level_unit='eV', output_order='wavelength', wavelength_type='vacuum', get_query_payload=False): """ Returns ------- response : `requests.Response` object The response of the HTTP request. """ request_payload = self._args_to_payload( minwav, maxwav, linename=linename, energy_level_unit=energy_level_unit, output_order=output_order, wavelength_type=wavelength_type) if get_query_payload: return request_payload response = self._request("GET", url=Nist.URL, params=request_payload, timeout=Nist.TIMEOUT) return response
def _parse_result(self, response, *, verbose=False): """ Parses the results from the HTTP response to `astropy.table.Table`. Parameters ---------- response : `requests.Response` The HTTP response object Returns ------- table : `astropy.table.Table` """ pre_re = re.compile("<pre>(.*)</pre>", flags=re.DOTALL) links_re = re.compile(r"<a.*?>\s*(\w+)\s*</a>") content = str(response.text) try: pre = pre_re.findall(content)[0] except IndexError: raise Exception("Result did not contain a table") try: table = _strip_blanks(pre) table = links_re.sub(r'\1', table) table = html.unescape(table) table = Table.read(table, format='ascii.fixed_width', data_start=3, delimiter='|') return table except Exception as ex: self.response = response self.table_parse_error = ex raise TableParseError("Failed to parse asciitable! The raw " "response can be found in self.response, " "and the error in self.table_parse_error.")
Nist = NistClass() def _parse_wavelength(min_wav, max_wav): """ Helper function to return wavelength and units in form accepted by NIST Parameters ---------- min_wav : `astropy.units.Quantity` object The lower wavelength in proper units. max_wav : `astropy.units.Quantity` object The upper wavelength in proper units. Returns ------- tuple : (number, number, number) The value of lower, upper wavelength and their unit. """ max_wav = max_wav.to(min_wav.unit) wav_unit = min_wav.unit.to_string() if wav_unit not in Nist.unit_code: max_wav = max_wav.to(u.angstrom).value min_wav = min_wav.to(u.angstrom).value wav_unit = Nist.unit_code['Angstrom'] else: max_wav = max_wav.value min_wav = min_wav.value wav_unit = Nist.unit_code[wav_unit] return (min_wav, max_wav, wav_unit)