def phase_bin_magseries_with_errs(phases, mags, errs,<EOL>binsize=<NUM_LIT>,<EOL>minbinelems=<NUM_LIT:7>):

<EOL>if not(phases.shape and mags.shape and len(phases) > <NUM_LIT:10> and len(mags) > <NUM_LIT:10>):<EOL><INDENT>LOGERROR("<STR_LIT>")<EOL>return<EOL><DEDENT>finiteind = np.isfinite(mags) & np.isfinite(phases) & np.isfinite(errs)<EOL>finite_phases = phases[finiteind]<EOL>finite_mags = mags[finiteind]<EOL>finite_errs = errs[finiteind]<EOL>nbins = int(np.ceil((np.nanmax(finite_phases) -<EOL>np.nanmin(finite_phases))/binsize) + <NUM_LIT:1>)<EOL>minphase = np.nanmin(finite_phases)<EOL>phasebins = [(minphase + x*binsize) for x in range(nbins)]<EOL>time_coords = np.array([[x,<NUM_LIT:1.0>] for x in finite_phases])<EOL>phasetree = cKDTree(time_coords)<EOL>binned_finite_phaseseries_indices = []<EOL>collected_binned_mags = {}<EOL>for phase in phasebins:<EOL><INDENT>bin_indices = phasetree.query_ball_point(np.array([phase,<NUM_LIT:1.0>]),<EOL>binsize/<NUM_LIT>, p=<NUM_LIT:1.0>)<EOL>if (bin_indices not in binned_finite_phaseseries_indices and<EOL>len(bin_indices) >= minbinelems):<EOL><INDENT>binned_finite_phaseseries_indices.append(bin_indices)<EOL><DEDENT><DEDENT>binned_finite_phaseseries_indices = [np.array(x) for x in<EOL>binned_finite_phaseseries_indices]<EOL>collected_binned_mags['<STR_LIT>'] = (<EOL>binned_finite_phaseseries_indices<EOL>)<EOL>collected_binned_mags['<STR_LIT>'] = phasebins<EOL>collected_binned_mags['<STR_LIT>'] = len(binned_finite_phaseseries_indices)<EOL>binned_phase = np.array([np.median(finite_phases[x])<EOL>for x in binned_finite_phaseseries_indices])<EOL>collected_binned_mags['<STR_LIT>'] = binned_phase<EOL>collected_binned_mags['<STR_LIT>'] = binsize<EOL>collected_binned_mags['<STR_LIT>'] = (<EOL>np.array([np.median(finite_mags[x])<EOL>for x in binned_finite_phaseseries_indices])<EOL>)<EOL>collected_binned_mags['<STR_LIT>'] = (<EOL>np.array([np.median(finite_errs[x])<EOL>for x in binned_finite_phaseseries_indices])<EOL>)<EOL>return collected_binned_mags<EOL>

Bins a phased magnitude/flux time-series using the bin size provided.

    Parameters
    ----------

    phases,mags,errs : np.array
        The phased magnitude/flux time-series and associated errs to bin in
        phase. Non-finite elements will be removed from these arrays. At least
        10 elements in each array are required for this function to operate.

    binsize : float
        The bin size to use to group together measurements closer than this
        amount in phase. This is in units of phase.

    minbinelems : int
        The minimum number of elements required per bin to include it in the
        output.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {'phasebin_indices': a list of the index arrays into the
                                 nan-filtered input arrays per each bin,
             'phasebins': list of bin boundaries for each bin,
             'nbins': the number of bins generated,
             'binnedphases': the phase values associated with each phase bin;
                            this is the median of the phase value in each bin,
             'binnedmags': the mag/flux values associated with each phase bin;
                           this is the median of the mags/fluxes in each bin,
             'binnederrs': the err values associated with each phase bin;
                           this is the median of the errs in each bin}


<EOL>finind = np.isfinite(times) & np.isfinite(mags) & np.isfinite(errs)<EOL>ftimes, fmags, ferrs = times[finind], mags[finind], errs[finind]<EOL>nzind = np.nonzero(ferrs)<EOL>ftimes, fmags, ferrs = ftimes[nzind], fmags[nzind], ferrs[nzind]<EOL>stimes, smags, serrs = sigclip_magseries(ftimes, fmags, ferrs,<EOL>magsarefluxes=magsarefluxes,<EOL>sigclip=sigclip)<EOL>if magsarefluxes:<EOL><INDENT>smags = smags / np.median(smags) - <NUM_LIT:1.0><EOL><DEDENT>else:<EOL><INDENT>smags = smags - np.median(smags)<EOL><DEDENT>if isinstance(fillgaps, float):<EOL><INDENT>gapfiller = fillgaps<EOL><DEDENT>elif isinstance(fillgaps, str) and fillgaps == '<STR_LIT>':<EOL><INDENT>smoothed = smags - savgol_filter(smags, filterwindow, <NUM_LIT:2>)<EOL>noiselevel = <NUM_LIT> * np.median(np.abs(smoothed - np.median(smoothed)))<EOL>gapfiller = noiselevel<EOL><DEDENT>elif isinstance(fillgaps, str) and fillgaps == '<STR_LIT>':<EOL><INDENT>gapfiller = np.nan<EOL><DEDENT>gaps = np.diff(stimes)<EOL>gapmoderes = scipy.stats.mode(gaps)<EOL>gapmode = gapmoderes[<NUM_LIT:0>].item()<EOL>LOGINFO('<STR_LIT>' % gapmode)<EOL>if forcetimebin:<EOL><INDENT>LOGWARNING('<STR_LIT>' %<EOL>forcetimebin)<EOL>gapmode = forcetimebin<EOL><DEDENT>if gapmode == <NUM_LIT:0.0>:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return None<EOL><DEDENT>starttime, endtime = np.min(stimes), np.max(stimes)<EOL>ntimes = int(np.ceil((endtime - starttime)/gapmode) + <NUM_LIT:1>)<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % ntimes)<EOL><DEDENT>interpolated_times = np.linspace(starttime, endtime, ntimes)<EOL>interpolated_mags = np.full_like(interpolated_times, gapfiller)<EOL>interpolated_errs = np.full_like(interpolated_times, gapfiller)<EOL>for ind, itime in enumerate(interpolated_times[:-<NUM_LIT:1>]):<EOL><INDENT>nextitime = itime + gapmode<EOL>itimeind = np.where((stimes > itime) & (stimes < nextitime))<EOL>if itimeind[<NUM_LIT:0>].size > <NUM_LIT:1>:<EOL><INDENT>interpolated_mags[ind] = np.median(smags[itimeind[<NUM_LIT:0>]])<EOL>interpolated_errs[ind] = np.median(serrs[itimeind[<NUM_LIT:0>]])<EOL><DEDENT>elif itimeind[<NUM_LIT:0>].size == <NUM_LIT:1>:<EOL><INDENT>interpolated_mags[ind] = smags[itimeind[<NUM_LIT:0>]]<EOL>interpolated_errs[ind] = serrs[itimeind[<NUM_LIT:0>]]<EOL><DEDENT><DEDENT>return {'<STR_LIT>':interpolated_times,<EOL>'<STR_LIT>':interpolated_mags,<EOL>'<STR_LIT>':interpolated_errs,<EOL>'<STR_LIT>':gapmode}<EOL>

This fills in gaps in a light curve.

    This is mainly intended for use in ACF period-finding, but maybe useful
    otherwise (i.e. when we figure out ARMA stuff for LCs). The main steps here
    are:

    - normalize the light curve to zero
    - remove giant outliers
    - interpolate gaps in the light curve
      (since ACF requires evenly spaced sampling)

    From McQuillan+ 2013a (https://doi.org/10.1093/mnras/stt536):

        "The ACF calculation requires the light curves to be regularly sampled
        and normalized to zero. We divided the flux in each quarter by its
        median and subtracted unity. Gaps in the light curve longer than the
        Kepler long cadence were filled using linear interpolation with added
        white Gaussian noise. This noise level was estimated using the variance
        of the residuals following subtraction of a smoothed version of the
        flux. To smooth the flux, we applied an iterative non-linear filter
        which consists of a median filter followed by a boxcar filter, both with
        11-point windows, with iterative 3σ clipping of outliers."

    Parameters
    ----------

    times,mags,errs : np.array
        The magnitude/flux time-series and associated measurement errors to
        operate on. Non-finite elements will be removed from these arrays. At
        least 10 elements in each array are required for this function to
        operate.

    fillgaps : {'noiselevel', 'nan'} or float
        If `fillgap='noiselevel'`, fills the gaps with the noise level obtained
        via the procedure above. If `fillgaps='nan'`, fills the gaps with
        `np.nan`. Otherwise, if `fillgaps` is a float, will use that value to
        fill the gaps. The default is to fill the gaps with 0.0 (as in
        McQuillan+ 2014) to "...prevent them contributing to the ACF".

    sigclip : float or int or sequence of two floats/ints or None
        If a single float or int, a symmetric sigma-clip will be performed using
        the number provided as the sigma-multiplier to cut out from the input
        time-series.

        If a list of two ints/floats is provided, the function will perform an
        'asymmetric' sigma-clip. The first element in this list is the sigma
        value to use for fainter flux/mag values; the second element in this
        list is the sigma value to use for brighter flux/mag values. For
        example, `sigclip=[10., 3.]`, will sigclip out greater than 10-sigma
        dimmings and greater than 3-sigma brightenings. Here the meaning of
        "dimming" and "brightening" is set by *physics* (not the magnitude
        system), which is why the `magsarefluxes` kwarg must be correctly set.

        If `sigclip` is None, no sigma-clipping will be performed, and the
        time-series (with non-finite elems removed) will be passed through to
        the output.

    magsareflux : bool
        True if your "mags" are in fact fluxes, i.e. if "fainter" corresponds to
        `mags` getting smaller.

    filterwindow : int
        The number of time-series points to include in the Savitsky-Golay filter
        operation when smoothing the light curve. This should be an odd integer.

    forcetimebin : float or None
        If `forcetimebin` is a float, this value will be used to generate the
        interpolated time series, effectively binning the light curve to this
        cadence. If `forcetimebin` is None, the mode of the gaps (the forward
        difference between successive time values in `times`) in the provided
        light curve will be used as the effective cadence. NOTE: `forcetimebin`
        must be in the same units as `times`, e.g. if times are JD then
        `forcetimebin` must be in days as well

    verbose : bool
        If this is True, will indicate progress at various stages in the
        operation.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {'itimes': the interpolated time values after gap-filling,
             'imags': the interpolated mag/flux values after gap-filling,
             'ierrs': the interpolated mag/flux values after gap-filling,
             'cadence': the cadence of the output mag/flux time-series}


if not email_user:<EOL><INDENT>email_user = EMAIL_USER<EOL><DEDENT>if not email_pass:<EOL><INDENT>email_pass = EMAIL_PASSWORD<EOL><DEDENT>if not email_server:<EOL><INDENT>email_server = EMAIL_SERVER<EOL><DEDENT>if not email_server and email_user and email_pass:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>msg_text = EMAIL_TEMPLATE.format(<EOL>sender=sender,<EOL>hostname=socket.gethostname(),<EOL>activity_time='<STR_LIT>' % datetime.utcnow().isoformat(),<EOL>activity_report=content<EOL>)<EOL>email_sender = '<STR_LIT>' % (sender, EMAIL_USER)<EOL>email_recipients = [('<STR_LIT>' % (x,y))<EOL>for (x,y) in zip(email_recipient_list,<EOL>email_address_list)]<EOL>email_msg = MIMEText(msg_text)<EOL>email_msg['<STR_LIT>'] = email_sender<EOL>email_msg['<STR_LIT>'] = '<STR_LIT:U+002CU+0020>'.join(email_recipients)<EOL>email_msg['<STR_LIT>'] = make_msgid()<EOL>email_msg['<STR_LIT>'] = '<STR_LIT>' % (<EOL>sender,<EOL>socket.gethostname(),<EOL>subject<EOL>)<EOL>email_msg['<STR_LIT>'] = formatdate(time.time())<EOL>try:<EOL><INDENT>server = smtplib.SMTP(EMAIL_SERVER, <NUM_LIT>)<EOL>server_ehlo_response = server.ehlo()<EOL>if server.has_extn('<STR_LIT>'):<EOL><INDENT>try:<EOL><INDENT>tls_start_response = server.starttls()<EOL>tls_ehlo_response = server.ehlo()<EOL>login_response = server.login(EMAIL_USER, EMAIL_PASSWORD)<EOL>send_response = (<EOL>server.sendmail(email_sender,<EOL>email_address_list,<EOL>email_msg.as_string())<EOL>)<EOL><DEDENT>except Exception as e:<EOL><INDENT>print('<STR_LIT>'<EOL>% e)<EOL>send_response = None<EOL><DEDENT>if send_response is not None:<EOL><INDENT>print('<STR_LIT>')<EOL>quit_response = server.quit()<EOL>return True<EOL><DEDENT>else:<EOL><INDENT>quit_response = server.quit()<EOL>return False<EOL><DEDENT><DEDENT>else:<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>quit_response = server.quit()<EOL>return False<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>print('<STR_LIT>' % e)<EOL>returnval = False<EOL><DEDENT>quit_response = server.quit()<EOL>return returnval<EOL>

This sends an email to addresses, informing them about events.

    The email account settings are retrieved from the settings file as described
    above.

    Parameters
    ----------

    sender : str
        The name of the sender to use in the email header.

    subject : str
        Subject of the email.

    content : str
        Content of the email.

    email_recipient list : list of str
        This is a list of email recipient names of the form:
        `['Example Person 1', 'Example Person 1', ...]`

    email_recipient list : list of str
        This is a list of email recipient addresses of the form:
        `['example1@example.com', 'example2@example.org', ...]`

    email_user : str
        The username of the email server account that will send the emails. If
        this is None, the value of EMAIL_USER from the
        ~/.astrobase/.emailsettings file will be used. If that is None as well,
        this function won't work.

    email_pass : str
        The password of the email server account that will send the emails. If
        this is None, the value of EMAIL_PASS from the
        ~/.astrobase/.emailsettings file will be used. If that is None as well,
        this function won't work.

    email_server : str
        The address of the email server that will send the emails. If this is
        None, the value of EMAIL_USER from the ~/.astrobase/.emailsettings file
        will be used. If that is None as well, this function won't work.

    Returns
    -------

    bool
        True if email sending succeeded. False if email sending failed.


dustparams = DUST_PARAMS.copy()<EOL>if coordtype == '<STR_LIT>':<EOL><INDENT>locstr = '<STR_LIT>' % (lon, lat)<EOL><DEDENT>elif coordtype == '<STR_LIT>':<EOL><INDENT>locstr = '<STR_LIT>' % (lon, lat)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>' % coordtype)<EOL>return None<EOL><DEDENT>dustparams['<STR_LIT>'] = locstr<EOL>dustparams['<STR_LIT>'] = '<STR_LIT>' % sizedeg<EOL>if '<STR_LIT>' in cachedir:<EOL><INDENT>cachedir = os.path.expanduser(cachedir)<EOL><DEDENT>if not os.path.exists(cachedir):<EOL><INDENT>os.makedirs(cachedir)<EOL><DEDENT>cachekey = '<STR_LIT>' % (locstr, sizedeg)<EOL>cachekey = hashlib.sha256(cachekey.encode()).hexdigest()<EOL>cachefname = os.path.join(cachedir, '<STR_LIT>' % cachekey)<EOL>provenance = '<STR_LIT>'<EOL>if forcefetch or (not os.path.exists(cachefname)):<EOL><INDENT>time.sleep(random.randint(<NUM_LIT:1>,jitter))<EOL>provenance = '<STR_LIT>'<EOL>try:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(lon, lat, coordtype, sizedeg))<EOL><DEDENT>req = requests.get(DUST_URL, dustparams, timeout=timeout)<EOL>req.raise_for_status()<EOL>resp = req.text<EOL>tableurl = DUST_REGEX.search(resp)<EOL>if tableurl:<EOL><INDENT>tableurl = tableurl.group(<NUM_LIT:0>)<EOL>req2 = requests.get(tableurl, timeout=timeout)<EOL>with open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>outfd.write(req2.content)<EOL><DEDENT>tablefname = cachefname<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' % (coordtype,<EOL>lon,lat,sizedeg))<EOL>LOGERROR('<STR_LIT>' % resp)<EOL>return None<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' % (coordtype,<EOL>lon,lat,sizedeg))<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT>' % (coordtype,<EOL>lon,lat,sizedeg))<EOL>return None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(lon, lat, coordtype, sizedeg))<EOL><DEDENT>tablefname = cachefname<EOL><DEDENT>extinction_table = Table.read(tablefname, format='<STR_LIT>')<EOL>filters = np.array(extinction_table['<STR_LIT>'])<EOL>a_sf11_byfilter = np.array(extinction_table['<STR_LIT>'])<EOL>a_sfd98_byfilter = np.array(extinction_table['<STR_LIT>'])<EOL>extdict = {'<STR_LIT>':{x:{'<STR_LIT>':y, '<STR_LIT>':z} for<EOL>x,y,z in zip(filters,a_sf11_byfilter,a_sfd98_byfilter)},<EOL>'<STR_LIT>':np.array(extinction_table),<EOL>'<STR_LIT>':os.path.abspath(cachefname),<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT>':'<STR_LIT>' % (coordtype,<EOL>lon,lat,<EOL>sizedeg)}<EOL>return extdict<EOL>

This queries the 2MASS DUST service to find the extinction parameters
    for the given `lon`, `lat`.

    Parameters
    ----------

    lon,lat: float
        These are decimal right ascension and declination if `coordtype =
        'equatorial'`. These are are decimal Galactic longitude and latitude if
        `coordtype = 'galactic'`.

    coordtype : {'equatorial','galactic'}
        Sets the type of coordinates passed in as `lon`, `lat`.

    sizedeg : float
        This is the width of the image returned by the DUST service. This can
        usually be left as-is if you're interested in the extinction only.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our request.

    jitter : float
        This is used to control the scale of the random wait in seconds before
        starting the query. Useful in parallelized situations.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {'Amag':{dict of extinction A_v values for several mag systems},
             'table': array containing the full extinction table,
             'tablefile': the path to the full extinction table file on disk,
             'provenance': 'cached' or 'new download',
             'request': string repr of the request made to 2MASS DUST}


def tic_single_object_crossmatch(ra, dec, radius):

for val in ra,dec,radius:<EOL><INDENT>if not isinstance(val, float):<EOL><INDENT>raise AssertionError('<STR_LIT>')<EOL><DEDENT><DEDENT>crossmatchInput = {"<STR_LIT>":[{"<STR_LIT:name>":"<STR_LIT>","<STR_LIT:type>":"<STR_LIT:float>"},<EOL>{"<STR_LIT:name>":"<STR_LIT>","<STR_LIT:type>":"<STR_LIT:float>"}],<EOL>"<STR_LIT:data>":[{"<STR_LIT>":ra,"<STR_LIT>":dec}]}<EOL>request = {"<STR_LIT>":"<STR_LIT>",<EOL>"<STR_LIT:data>":crossmatchInput,<EOL>"<STR_LIT>":{<EOL>"<STR_LIT>":"<STR_LIT>",<EOL>"<STR_LIT>":"<STR_LIT>",<EOL>"<STR_LIT>":radius<EOL>},<EOL>"<STR_LIT>":"<STR_LIT>",<EOL>'<STR_LIT>':True}<EOL>headers,out_string = _mast_query(request)<EOL>out_data = json.loads(out_string)<EOL>return out_data<EOL>

This does a cross-match against the TIC catalog on MAST.

    Speed tests: about 10 crossmatches per second. (-> 3 hours for 10^5 objects
    to crossmatch).

    Parameters
    ----------

    ra,dec : np.array
        The coordinates to cross match against, all in decimal degrees.

    radius : float
        The cross-match radius to use, in decimal degrees.

    Returns
    -------

    dict
        Returns the match results JSON from MAST loaded into a dict.


def massradius(age, planetdist, coremass,<EOL>mass='<STR_LIT>',<EOL>radius='<STR_LIT>'):

MR = {<NUM_LIT>:MASSESRADII_0_3GYR,<EOL><NUM_LIT:1.0>:MASSESRADII_1_0GYR,<EOL><NUM_LIT>:MASSESRADII_4_5GYR}<EOL>if age not in MR:<EOL><INDENT>print('<STR_LIT>')<EOL>return<EOL><DEDENT>massradius = MR[age]<EOL>if (planetdist in massradius) and (coremass in massradius[planetdist]):<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>' % (age, planetdist, coremass))<EOL>massradrelation = massradius[planetdist][coremass]<EOL>outdict = {'<STR_LIT>':array(massradrelation[mass]),<EOL>'<STR_LIT>':array(massradrelation[radius])}<EOL>return outdict<EOL><DEDENT>

This function gets the Fortney mass-radius relation for planets.

    Parameters
    ----------

    age : float
        This should be one of: 0.3, 1.0, 4.5 [in Gyr].

    planetdist : float
        This should be one of: 0.02, 0.045, 0.1, 1.0, 9.5 [in AU]

    coremass : int
        This should be one of: 0, 10, 25, 50, 100 [in Mearth]

    mass : {'massjupiter','massearth'}
        Sets the mass units.

    radius : str
        Sets the radius units. Only 'radiusjupiter' is used for now.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {'mass': an array containing the masses to plot),
             'radius': an array containing the radii to plot}

        These can be passed to a plotting routine to make mass-radius plot for
        the specified age, planet-star distance, and core-mass.


<EOL>inputparams = TAP_PARAMS.copy()<EOL>inputparams['<STR_LIT>'] = querystr[::]<EOL>if returnformat in RETURN_FORMATS:<EOL><INDENT>inputparams['<STR_LIT>'] = returnformat<EOL><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>' %<EOL>returnformat)<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>'<EOL><DEDENT>if '<STR_LIT>' in cachedir:<EOL><INDENT>cachedir = os.path.expanduser(cachedir)<EOL><DEDENT>if not os.path.exists(cachedir):<EOL><INDENT>os.makedirs(cachedir)<EOL><DEDENT>xcachekey = '<STR_LIT:->'.join([repr(inputparams[x])<EOL>for x in sorted(inputparams.keys())])<EOL>cachekey = hashlib.sha256(xcachekey.encode()).hexdigest()<EOL>cachefname = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % (cachekey, RETURN_FORMATS[returnformat])<EOL>)<EOL>provenance = '<STR_LIT>'<EOL>incomplete_qpklf = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % cachekey<EOL>)<EOL>if (not forcefetch and<EOL>complete_query_later and<EOL>os.path.exists(incomplete_qpklf)):<EOL><INDENT>with open(incomplete_qpklf, '<STR_LIT:rb>') as infd:<EOL><INDENT>incomplete_qinfo = pickle.load(infd)<EOL><DEDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>waitdone = False<EOL>timeelapsed = <NUM_LIT:0.0><EOL>simbad_mirror = incomplete_qinfo['<STR_LIT>']<EOL>status_url = incomplete_qinfo['<STR_LIT>']<EOL>phasekeyword = incomplete_qinfo['<STR_LIT>']<EOL>resultkeyword = incomplete_qinfo['<STR_LIT>']<EOL>while not waitdone:<EOL><INDENT>if timeelapsed > maxtimeout:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout,<EOL>repr(inputparams),<EOL>status_url))<EOL>return None<EOL><DEDENT>try:<EOL><INDENT>resreq = requests.get(status_url,<EOL>timeout=timeout)<EOL>resreq.raise_for_status()<EOL>resxml = parseString(resreq.text)<EOL>jobstatuselem = (<EOL>resxml.getElementsByTagName(phasekeyword)[<NUM_LIT:0>]<EOL>)<EOL>jobstatus = jobstatuselem.firstChild.toxml()<EOL>if jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>waitdone = True<EOL><DEDENT>elif jobstatus != '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (timeelapsed, jobstatus, status_url))<EOL><DEDENT>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(status_url,<EOL>resreq.text))<EOL>os.remove(incomplete_qpklf)<EOL>return None<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), status_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>status_url,<EOL>resreq.text)<EOL>)<EOL>os.remove(incomplete_qpklf)<EOL>return None<EOL><DEDENT><DEDENT>LOGINFO('<STR_LIT>')<EOL>result_url_elem = resxml.getElementsByTagName(resultkeyword)[<NUM_LIT:0>]<EOL>result_url = result_url_elem.getAttribute('<STR_LIT>')<EOL>result_nrows = result_url_elem.getAttribute('<STR_LIT>')<EOL>try:<EOL><INDENT>resreq = requests.get(result_url, timeout=timeout)<EOL>resreq.raise_for_status()<EOL>if cachefname.endswith('<STR_LIT>'):<EOL><INDENT>with gzip.open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>with open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % result_nrows)<EOL><DEDENT>tablefname = cachefname<EOL>provenance = '<STR_LIT>'<EOL>resdict = {'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT:result>':tablefname}<EOL>os.remove(incomplete_qpklf)<EOL>return resdict<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), result_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>result_url,<EOL>resreq.status_code)<EOL>)<EOL>os.remove(incomplete_qpklf)<EOL>return None<EOL><DEDENT><DEDENT>if forcefetch or (not os.path.exists(cachefname)):<EOL><INDENT>provenance = '<STR_LIT>'<EOL>time.sleep(random.randint(<NUM_LIT:1>,jitter))<EOL>jobid = '<STR_LIT>' % time.time()<EOL>inputparams['<STR_LIT>'] = jobid<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>'<EOL>try:<EOL><INDENT>waitdone = False<EOL>timeelapsed = <NUM_LIT:0.0><EOL>if simbad_mirror is not None and simbad_mirror in SIMBAD_URLS:<EOL><INDENT>tapurl = SIMBAD_URLS[simbad_mirror]['<STR_LIT:url>']<EOL>resultkeyword = SIMBAD_URLS[simbad_mirror]['<STR_LIT>']<EOL>phasekeyword = SIMBAD_URLS[simbad_mirror]['<STR_LIT>']<EOL>randkey = simbad_mirror<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=SIMBAD_URLS[simbad_mirror]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>randkey = random.choice(list(SIMBAD_URLS.keys()))<EOL>tapurl = SIMBAD_URLS[randkey]['<STR_LIT:url>']<EOL>resultkeyword = SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>phasekeyword = SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % tapurl)<EOL><DEDENT><DEDENT>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>% repr(inputparams)<EOL>)<EOL><DEDENT>mirrorok = False<EOL>ntries = <NUM_LIT:1><EOL>while (not mirrorok):<EOL><INDENT>if ntries > maxtries:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>maxtries)<EOL>return None<EOL><DEDENT>try:<EOL><INDENT>req = requests.post(tapurl,<EOL>data=inputparams,<EOL>timeout=timeout)<EOL>resp_status = req.status_code<EOL>req.raise_for_status()<EOL>mirrorok = True<EOL><DEDENT>except requests.exceptions.HTTPError as e:<EOL><INDENT>LOGWARNING(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% tapurl<EOL>)<EOL>mirrorok = False<EOL>remainingmirrors = list(SIMBAD_URLS.keys())<EOL>waittime = random.choice(range(<NUM_LIT:1>,<NUM_LIT:6>))<EOL>time.sleep(waittime)<EOL>randkey = remainingmirrors[<NUM_LIT:0>]<EOL>tapurl = SIMBAD_URLS[randkey]['<STR_LIT:url>']<EOL>resultkeyword = SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>phasekeyword = SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGWARNING(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL>mirrorok = False<EOL>remainingmirrors = list(SIMBAD_URLS.keys())<EOL>waittime = random.choice(range(<NUM_LIT:1>,<NUM_LIT:6>))<EOL>time.sleep(waittime)<EOL>randkey = remainingmirrors[<NUM_LIT:0>]<EOL>tapurl = SIMBAD_URLS[randkey]['<STR_LIT:url>']<EOL>resultkeyword = SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>phasekeyword = SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=SIMBAD_URLS[randkey]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT><DEDENT>ntries = ntries + <NUM_LIT:1><EOL><DEDENT>status_url = req.url<EOL>resxml = parseString(req.text)<EOL>jobstatuselem = resxml.getElementsByTagName(phasekeyword)<EOL>if jobstatuselem:<EOL><INDENT>jobstatuselem = jobstatuselem[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' % phasekeyword)<EOL>LOGERROR('<STR_LIT:%s>' % req.txt)<EOL>req.close()<EOL>return None<EOL><DEDENT>jobstatus = jobstatuselem.firstChild.toxml()<EOL>if jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>waitdone = True<EOL><DEDENT><DEDENT>elif jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGERROR(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>status_url,<EOL>req.text)<EOL>)<EOL>return None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % jobstatus<EOL>)<EOL><DEDENT>while not waitdone:<EOL><INDENT>if timeelapsed > maxtimeout:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout,<EOL>repr(inputparams),<EOL>status_url,<EOL>jobstatus))<EOL>if complete_query_later and jobstatus in ('<STR_LIT>',<EOL>'<STR_LIT>'):<EOL><INDENT>incomplete_qpklf = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % cachekey<EOL>)<EOL>with open(incomplete_qpklf, '<STR_LIT:wb>') as outfd:<EOL><INDENT>savedict = inputparams.copy()<EOL>savedict['<STR_LIT>'] = status_url<EOL>savedict['<STR_LIT>'] = jobstatus<EOL>savedict['<STR_LIT>'] = simbad_mirror<EOL>savedict['<STR_LIT>'] = phasekeyword<EOL>savedict['<STR_LIT>'] = resultkeyword<EOL>pickle.dump(savedict,<EOL>outfd,<EOL>pickle.HIGHEST_PROTOCOL)<EOL><DEDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>jobstatus)<EOL><DEDENT>return None<EOL><DEDENT>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL>try:<EOL><INDENT>resreq = requests.get(status_url, timeout=timeout)<EOL>resreq.raise_for_status()<EOL>resxml = parseString(resreq.text)<EOL>jobstatuselem = (<EOL>resxml.getElementsByTagName(phasekeyword)[<NUM_LIT:0>]<EOL>)<EOL>jobstatus = jobstatuselem.firstChild.toxml()<EOL>if jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>waitdone = True<EOL><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (timeelapsed, jobstatus, status_url))<EOL><DEDENT>continue<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), status_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>status_url,<EOL>resreq.text)<EOL>)<EOL>return None<EOL><DEDENT><DEDENT><DEDENT>result_url_elem = resxml.getElementsByTagName(resultkeyword)[<NUM_LIT:0>]<EOL>result_url = result_url_elem.getAttribute('<STR_LIT>')<EOL>result_nrows = result_url_elem.getAttribute('<STR_LIT>')<EOL>try:<EOL><INDENT>resreq = requests.get(result_url, timeout=timeout)<EOL>resreq.raise_for_status()<EOL>if cachefname.endswith('<STR_LIT>'):<EOL><INDENT>with gzip.open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>with open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % result_nrows)<EOL><DEDENT>tablefname = cachefname<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), result_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>result_url,<EOL>resreq.status_code)<EOL>)<EOL>return None<EOL><DEDENT><DEDENT>except requests.exceptions.HTTPError as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT>' % (resp_status,<EOL>repr(inputparams)))<EOL>return None<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>if '<STR_LIT>' in locals():<EOL><INDENT>LOGERROR('<STR_LIT>' % req.text)<EOL><DEDENT>return None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams)))<EOL><DEDENT>tablefname = cachefname<EOL>try:<EOL><INDENT>infd = gzip.open(cachefname,'<STR_LIT:rb>')<EOL>simbad_objectnames = np.genfromtxt(<EOL>infd,<EOL>names=True,<EOL>delimiter='<STR_LIT:U+002C>',<EOL>dtype='<STR_LIT>',<EOL>usecols=(<NUM_LIT:0>,<NUM_LIT:1>,<NUM_LIT:2>,<NUM_LIT:3>,<NUM_LIT:4>,<NUM_LIT:5>,<NUM_LIT:6>,<NUM_LIT:7>,<NUM_LIT:8>),<EOL>comments='<STR_LIT:?>',  <EOL>)<EOL>infd.close()<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT>' % cachefname)<EOL>return tap_query(querystr,<EOL>simbad_mirror=simbad_mirror,<EOL>returnformat=returnformat,<EOL>forcefetch=True,<EOL>cachedir=cachedir,<EOL>verbose=verbose,<EOL>timeout=timeout,<EOL>refresh=refresh,<EOL>maxtimeout=maxtimeout)<EOL><DEDENT><DEDENT>resdict = {'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT:result>':tablefname}<EOL>return resdict<EOL>

This queries the SIMBAD TAP service using the ADQL query string provided.

    Parameters
    ----------

    querystr : str
        This is the ADQL query string. See:
        http://www.ivoa.net/documents/ADQL/2.0 for the specification.

    simbad_mirror : str
        This is the key used to select a SIMBAD mirror from the
        `SIMBAD_URLS` dict above. If set, the specified mirror will be used. If
        None, a random mirror chosen from that dict will be used.

    returnformat : {'csv','votable','json'}
        The returned file format to request from the GAIA catalog service.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    complete_query_later : bool
        If set to True, a submitted query that does not return a result before
        `maxtimeout` has passed will be cancelled but its input request
        parameters and the result URL provided by the service will be saved. If
        this function is then called later with these same input request
        parameters, it will check if the query finally finished and a result is
        available. If so, will download the results instead of submitting a new
        query. If it's not done yet, will start waiting for results again. To
        force launch a new query with the same request parameters, set the
        `forcefetch` kwarg to True.

    jitter : float
        This is used to control the scale of the random wait in seconds before
        starting the query. Useful in parallelized situations.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


This queries the SIMBAD TAP service for a list of object names near the
    coords. This is effectively a "reverse" name resolver (i.e. this does the
    opposite of SESAME).

    Parameters
    ----------

    racenter,declcenter : float
        The cone-search center coordinates in decimal degrees

    searchradiusarcsec : float
        The radius in arcseconds to search around the center coordinates.

    simbad_mirror : str
        This is the key used to select a SIMBAD mirror from the
        `SIMBAD_URLS` dict above. If set, the specified mirror will be used. If
        None, a random mirror chosen from that dict will be used.

    returnformat : {'csv','votable','json'}
        The returned file format to request from the GAIA catalog service.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    complete_query_later : bool
        If set to True, a submitted query that does not return a result before
        `maxtimeout` has passed will be cancelled but its input request
        parameters and the result URL provided by the service will be saved. If
        this function is then called later with these same input request
        parameters, it will check if the query finally finished and a result is
        available. If so, will download the results instead of submitting a new
        query. If it's not done yet, will start waiting for results again. To
        force launch a new query with the same request parameters, set the
        `forcefetch` kwarg to True.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


print('<STR_LIT>' % ('<STR_LIT>','<STR_LIT>'))<EOL>print('<STR_LIT>' % ('<STR_LIT>','<STR_LIT>'))<EOL>for key in sorted(TRILEGAL_FILTER_SYSTEMS.keys()):<EOL><INDENT>print('<STR_LIT>' % (key, TRILEGAL_FILTER_SYSTEMS[key]['<STR_LIT>']))<EOL><DEDENT>

This just lists all the filter systems available for TRILEGAL.


<EOL>inputparams = copy.deepcopy(TRILEGAL_INPUT_PARAMS)<EOL>inputparams['<STR_LIT>'] = '<STR_LIT:1>' if usebinaries else '<STR_LIT:0>'<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>' % extinction_sigma<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>' % field_deg2<EOL>inputparams['<STR_LIT>'] = str(maglim_filtercol)<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>' % magnitude_limit<EOL>inputparams['<STR_LIT>'] = str(trilegal_version)<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>' % gal_lon<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>' % gal_lat<EOL>if field_deg2 > <NUM_LIT>:<EOL><INDENT>LOGERROR("<STR_LIT>")<EOL>return None<EOL><DEDENT>extinction_info = dust.extinction_query(gal_lon,<EOL>gal_lat,<EOL>coordtype='<STR_LIT>',<EOL>forcefetch=forcefetch,<EOL>verbose=verbose,<EOL>timeout=timeout)<EOL>try:<EOL><INDENT>Av_infinity = extinction_info['<STR_LIT>']['<STR_LIT>']['<STR_LIT>']<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>' % Av_infinity<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % (gal_lon, gal_lat,<EOL>inputparams['<STR_LIT>'])<EOL>)<EOL><DEDENT>if filtersystem in TRILEGAL_FILTER_SYSTEMS:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>TRILEGAL_FILTER_SYSTEMS[filtersystem]['<STR_LIT>']<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % filtersystem)<EOL>return None<EOL><DEDENT>trilegal_params = copy.deepcopy(TRILEGAL_DEFAULT_PARAMS)<EOL>trilegal_params.update(inputparams)<EOL>if extraparams and isinstance(extraparams, dict):<EOL><INDENT>trilegal_params.update(extraparams)<EOL><DEDENT>if '<STR_LIT>' in cachedir:<EOL><INDENT>cachedir = os.path.expanduser(cachedir)<EOL><DEDENT>if not os.path.exists(cachedir):<EOL><INDENT>os.makedirs(cachedir)<EOL><DEDENT>cachekey = repr(inputparams)<EOL>cachekey = hashlib.sha256(cachekey.encode()).hexdigest()<EOL>cachefname = os.path.join(cachedir, '<STR_LIT>' % cachekey)<EOL>provenance = '<STR_LIT>'<EOL>lockfile = os.path.join(cachedir, '<STR_LIT>' % cachekey)<EOL>if forcefetch or (not os.path.exists(cachefname)):<EOL><INDENT>if os.path.exists(lockfile):<EOL><INDENT>with open(lockfile,'<STR_LIT:r>') as infd:<EOL><INDENT>lock_contents = infd.read()<EOL><DEDENT>lock_contents = lock_contents.replace('<STR_LIT:\n>','<STR_LIT>')<EOL>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>lock_contents)<EOL>return None<EOL><DEDENT>else:<EOL><INDENT>with open(lockfile,'<STR_LIT:w>') as outfd:<EOL><INDENT>outfd.write(datetime.utcnow().isoformat())<EOL><DEDENT><DEDENT>provenance = '<STR_LIT>'<EOL>try:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>% repr(inputparams))<EOL><DEDENT>posturl = TRILEGAL_POSTURL.format(formversion=trilegal_version)<EOL>req = requests.post(posturl,<EOL>data=trilegal_params,<EOL>timeout=timeout)<EOL>resp = req.text<EOL>resultfile = TRILEGAL_REGEX.search(resp)<EOL>if resultfile:<EOL><INDENT>resultfile = resultfile[<NUM_LIT:0>]<EOL>waitdone = False<EOL>timeelapsed = <NUM_LIT:0.0><EOL>resultfileurl = '<STR_LIT>' % (<EOL>TRILEGAL_BASEURL,<EOL>resultfile.replace('<STR_LIT>','<STR_LIT>')<EOL>)<EOL>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>while not waitdone:<EOL><INDENT>if timeelapsed > maxtimeout:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>if os.path.exists(lockfile):<EOL><INDENT>os.remove(lockfile)<EOL><DEDENT>return None<EOL><DEDENT>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL>try:<EOL><INDENT>resreq = requests.get(resultfileurl)<EOL>resreq.raise_for_status()<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL><DEDENT>with gzip.open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT>tablefname = cachefname<EOL>waitdone = True<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (timeelapsed, resultfileurl))<EOL><DEDENT>continue<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>LOGINFO(resp)<EOL>if os.path.exists(lockfile):<EOL><INDENT>os.remove(lockfile)<EOL><DEDENT>return None<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>return None<EOL><DEDENT>finally:<EOL><INDENT>if os.path.exists(lockfile):<EOL><INDENT>os.remove(lockfile)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams)))<EOL><DEDENT>tablefname = cachefname<EOL><DEDENT>resdict = {'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':extraparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT>':tablefname}<EOL>return resdict<EOL>

This queries the TRILEGAL model form, downloads results, and parses them.

    Parameters
    ----------

    gal_lon,gal_lat : float
        These are the center galactic longitude and latitude in degrees.

    filtersystem : str
        This is a key in the TRILEGAL_FILTER_SYSTEMS dict. Use the function
        :py:func:`astrobase.services.trilegal.list_trilegal_filtersystems` to
        see a nicely formatted table with the key and description for each of
        these.

    field_deg2 : float
        The area of the simulated field in square degrees.

    usebinaries : bool
        If this is True, binaries will be present in the model results.

    extinction_sigma : float
        This is the applied std dev around the `Av_extinction` value for the
        galactic coordinates requested.

    magnitude_limit : float
        This is the limiting magnitude of the simulation in the
        `maglim_filtercol` band index of the filter system chosen.

    maglim_filtercol : int
        The index in the filter system list of the magnitude limiting band.

    trilegal_version : float
        This is the the version of the TRILEGAL form to use. This can usually be
        left as-is.

    extraparams : dict or None
        This is a dict that can be used to override parameters of the model
        other than the basic ones used for input to this function. All
        parameters are listed in `TRILEGAL_DEFAULT_PARAMS` above. See:

        http://stev.oapd.inaf.it/cgi-bin/trilegal

        for explanations of these parameters.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    Returns
    -------

    dict
        This returns a dict of the form::

            {'params':the input param dict used,
             'extraparams':any extra params used,
             'provenance':'cached' or 'new download',
             'tablefile':the path on disk to the downloaded model text file}


This runs the TRILEGAL query for decimal equatorial coordinates.

    Parameters
    ----------

    ra,decl : float
        These are the center equatorial coordinates in decimal degrees

    filtersystem : str
        This is a key in the TRILEGAL_FILTER_SYSTEMS dict. Use the function
        :py:func:`astrobase.services.trilegal.list_trilegal_filtersystems` to
        see a nicely formatted table with the key and description for each of
        these.

    field_deg2 : float
        The area of the simulated field in square degrees. This is in the
        Galactic coordinate system.

    usebinaries : bool
        If this is True, binaries will be present in the model results.

    extinction_sigma : float
        This is the applied std dev around the `Av_extinction` value for the
        galactic coordinates requested.

    magnitude_limit : float
        This is the limiting magnitude of the simulation in the
        `maglim_filtercol` band index of the filter system chosen.

    maglim_filtercol : int
        The index in the filter system list of the magnitude limiting band.

    trilegal_version : float
        This is the the version of the TRILEGAL form to use. This can usually be
        left as-is.

    extraparams : dict or None
        This is a dict that can be used to override parameters of the model
        other than the basic ones used for input to this function. All
        parameters are listed in `TRILEGAL_DEFAULT_PARAMS` above. See:

        http://stev.oapd.inaf.it/cgi-bin/trilegal

        for explanations of these parameters.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    Returns
    -------

    dict
        This returns a dict of the form::

            {'params':the input param dict used,
             'extraparams':any extra params used,
             'provenance':'cached' or 'new download',
             'tablefile':the path on disk to the downloaded model text file}


infd = gzip.open(modelfile)<EOL>model = np.genfromtxt(infd,names=True)<EOL>infd.close()<EOL>return model<EOL>

This reads a downloaded TRILEGAL model file.

Parameters
----------

modelfile : str
    Path to the downloaded model file to read.

Returns
-------

np.recarray
    Returns the model table as a Numpy record array.


<EOL>inputparams = {<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':params,<EOL>'<STR_LIT>':service,<EOL>'<STR_LIT>':timeout,<EOL>}<EOL>if data is not None:<EOL><INDENT>inputparams['<STR_LIT:data>'] = data<EOL><DEDENT>if '<STR_LIT>' in cachedir:<EOL><INDENT>cachedir = os.path.expanduser(cachedir)<EOL><DEDENT>if not os.path.exists(cachedir):<EOL><INDENT>os.makedirs(cachedir)<EOL><DEDENT>xcachekey = '<STR_LIT:->'.join([repr(inputparams[x])<EOL>for x in sorted(inputparams.keys())])<EOL>cachekey = hashlib.sha256(xcachekey.encode()).hexdigest()<EOL>cachefname = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % (cachekey,)<EOL>)<EOL>provenance = '<STR_LIT>'<EOL>if forcefetch or (not os.path.exists(cachefname)):<EOL><INDENT>time.sleep(random.randint(<NUM_LIT:1>,jitter))<EOL>provenance = '<STR_LIT>'<EOL>waitdone = False<EOL>timeelapsed = <NUM_LIT:0.0><EOL>ntries = <NUM_LIT:1><EOL>url = MAST_URLS[apiversion]['<STR_LIT:url>']<EOL>formdata = {'<STR_LIT>':json.dumps(inputparams)}<EOL>while (not waitdone) or (ntries < maxtries):<EOL><INDENT>if timeelapsed > maxtimeout:<EOL><INDENT>retdict = None<EOL>break<EOL><DEDENT>try:<EOL><INDENT>resp = requests.post(url,<EOL>data=formdata,<EOL>timeout=timeout+<NUM_LIT:1.0>)<EOL>resp.raise_for_status()<EOL>respjson = resp.json()<EOL>if respjson['<STR_LIT:status>'] == '<STR_LIT>':<EOL><INDENT>data = respjson['<STR_LIT:data>']<EOL>nrows = len(data)<EOL>if nrows > <NUM_LIT:0>:<EOL><INDENT>with open(cachefname, '<STR_LIT:w>') as outfd:<EOL><INDENT>json.dump(respjson, outfd)<EOL><DEDENT>retdict = {<EOL>'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT>':cachefname<EOL>}<EOL>waitdone = True<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % nrows)<EOL><DEDENT>break<EOL><DEDENT>else:<EOL><INDENT>LOGERROR(<EOL>'<STR_LIT>' %<EOL>inputparams<EOL>)<EOL>retdict = None<EOL>waitdone = True<EOL>break<EOL><DEDENT><DEDENT>elif respjson['<STR_LIT:status>'] == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' % refresh)<EOL><DEDENT>waitdone = False<EOL>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL>retdict = None<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>respjson['<STR_LIT>'])<EOL>retdict = None<EOL>waitdone = True<EOL>break<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>if verbose:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>refresh)<EOL><DEDENT>waitdone = False<EOL>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL>retdict = None<EOL><DEDENT>except KeyboardInterrupt as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>')<EOL>if raiseonfail:<EOL><INDENT>raise<EOL><DEDENT>return None<EOL><DEDENT>ntries = ntries + <NUM_LIT:1><EOL><DEDENT>if retdict is None:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' % inputparams)<EOL>return None<EOL><DEDENT>else:<EOL><INDENT>return retdict<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams)))<EOL><DEDENT>retdict = {<EOL>'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT>':cachefname<EOL>}<EOL>return retdict<EOL><DEDENT>

This queries the STScI MAST service for catalog data.

    All results are downloaded as JSON files that are written to `cachedir`.

    Parameters
    ----------

    service : str
        This is the name of the service to use. See
        https://mast.stsci.edu/api/v0/_services.html for a list of all available
        services.

    params : dict
        This is a dict containing the input params to the service as described
        on its details page linked in the `service description page on MAST
        <https://mast.stsci.edu/api/v0/_services.html>`_.

    data : dict or None
        This contains optional data to upload to the service.

    apiversion : str
        The API version of the MAST service to use. This sets the URL that this
        function will call, using `apiversion` as key into the `MAST_URLS` dict
        above.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    raiseonfail : bool
        If this is True, the function will raise an Exception if something goes
        wrong, instead of returning None.

    jitter : float
        This is used to control the scale of the random wait in seconds before
        starting the query. Useful in parallelized situations.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


This runs a TESS Input Catalog cone search on MAST.

    If you use this, please cite the TIC paper (Stassun et al 2018;
    http://adsabs.harvard.edu/abs/2018AJ....156..102S). Also see the "living"
    TESS input catalog docs:

    https://docs.google.com/document/d/1zdiKMs4Ld4cXZ2DW4lMX-fuxAF6hPHTjqjIwGqnfjqI

    Also see: https://mast.stsci.edu/api/v0/_t_i_cfields.html for the fields
    returned by the service and present in the result JSON file.

    Parameters
    ----------

    ra,decl : float
        The center coordinates of the cone-search in decimal degrees.

    radius_arcmin : float
        The cone-search radius in arcminutes.

    apiversion : str
        The API version of the MAST service to use. This sets the URL that this
        function will call, using `apiversion` as key into the `MAST_URLS` dict
        above.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    jitter : float
        This is used to control the scale of the random wait in seconds before
        starting the query. Useful in parallelized situations.

    raiseonfail : bool
        If this is True, the function will raise an Exception if something goes
        wrong, instead of returning None.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


service = '<STR_LIT>'<EOL>xmatch_input = {'<STR_LIT>':[{'<STR_LIT:name>':'<STR_LIT>','<STR_LIT:type>':'<STR_LIT:float>'},<EOL>{'<STR_LIT:name>':'<STR_LIT>','<STR_LIT:type>':'<STR_LIT:float>'}]}<EOL>xmatch_input['<STR_LIT:data>'] = [{'<STR_LIT>':x, '<STR_LIT>':y} for (x,y) in zip(ra, decl)]<EOL>params = {'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':radius_arcsec/<NUM_LIT>}<EOL>return mast_query(service,<EOL>params,<EOL>data=xmatch_input,<EOL>jitter=jitter,<EOL>apiversion=apiversion,<EOL>forcefetch=forcefetch,<EOL>cachedir=cachedir,<EOL>verbose=verbose,<EOL>timeout=timeout,<EOL>refresh=refresh,<EOL>maxtimeout=maxtimeout,<EOL>maxtries=maxtries,<EOL>raiseonfail=raiseonfail)<EOL>

This does a cross-match with TIC.

    Parameters
    ----------

    ra,decl : np.arrays or lists of floats
        The coordinates that will be cross-matched against the TIC.

    radius_arcsec : float
        The cross-match radius in arcseconds.

    apiversion : str
        The API version of the MAST service to use. This sets the URL that this
        function will call, using `apiversion` as key into the `MAST_URLS` dict
        above.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    jitter : float
        This is used to control the scale of the random wait in seconds before
        starting the query. Useful in parallelized situations.

    raiseonfail : bool
        If this is True, the function will raise an Exception if something goes
        wrong, instead of returning None.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


This runs a TIC search for a specified TIC ID.

Parameters
----------

objectid : str
    The object ID to look up information for.

idcol_to_use : str
    This is the name of the object ID column to use when looking up the
    provided `objectid`. This is one of {'ID', 'HIP', 'TYC', 'UCAC',
    'TWOMASS', 'ALLWISE', 'SDSS', 'GAIA', 'APASS', 'KIC'}.

apiversion : str
    The API version of the MAST service to use. This sets the URL that this
    function will call, using `apiversion` as key into the `MAST_URLS` dict
    above.

forcefetch : bool
    If this is True, the query will be retried even if cached results for
    it exist.

cachedir : str
    This points to the directory where results will be downloaded.

verbose : bool
    If True, will indicate progress and warn of any issues.

timeout : float
    This sets the amount of time in seconds to wait for the service to
    respond to our initial request.

refresh : float
    This sets the amount of time in seconds to wait before checking if the
    result file is available. If the results file isn't available after
    `refresh` seconds have elapsed, the function will wait for `refresh`
    seconds continuously, until `maxtimeout` is reached or the results file
    becomes available.

maxtimeout : float
    The maximum amount of time in seconds to wait for a result to become
    available after submitting our query request.

maxtries : int
    The maximum number of tries (across all mirrors tried) to make to either
    submit the request or download the results, before giving up.

jitter : float
    This is used to control the scale of the random wait in seconds before
    starting the query. Useful in parallelized situations.

raiseonfail : bool
    If this is True, the function will raise an Exception if something goes
    wrong, instead of returning None.

Returns
-------

dict
    This returns a dict of the following form::

        {'params':dict of the input params used for the query,
         'provenance':'cache' or 'new download',
         'result':path to the file on disk with the downloaded data table}


<EOL>inputparams = TAP_PARAMS.copy()<EOL>inputparams['<STR_LIT>'] = querystr[::]<EOL>if returnformat in RETURN_FORMATS:<EOL><INDENT>inputparams['<STR_LIT>'] = returnformat<EOL><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>' %<EOL>returnformat)<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>'<EOL><DEDENT>if '<STR_LIT>' in cachedir:<EOL><INDENT>cachedir = os.path.expanduser(cachedir)<EOL><DEDENT>if not os.path.exists(cachedir):<EOL><INDENT>os.makedirs(cachedir)<EOL><DEDENT>xcachekey = '<STR_LIT:->'.join([repr(inputparams[x])<EOL>for x in sorted(inputparams.keys())])<EOL>cachekey = hashlib.sha256(xcachekey.encode()).hexdigest()<EOL>cachefname = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % (cachekey, RETURN_FORMATS[returnformat])<EOL>)<EOL>provenance = '<STR_LIT>'<EOL>incomplete_qpklf = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % cachekey<EOL>)<EOL>if (not forcefetch and<EOL>complete_query_later and<EOL>os.path.exists(incomplete_qpklf)):<EOL><INDENT>with open(incomplete_qpklf, '<STR_LIT:rb>') as infd:<EOL><INDENT>incomplete_qinfo = pickle.load(infd)<EOL><DEDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>waitdone = False<EOL>timeelapsed = <NUM_LIT:0.0><EOL>gaia_mirror = incomplete_qinfo['<STR_LIT>']<EOL>status_url = incomplete_qinfo['<STR_LIT>']<EOL>phasekeyword = incomplete_qinfo['<STR_LIT>']<EOL>resultkeyword = incomplete_qinfo['<STR_LIT>']<EOL>while not waitdone:<EOL><INDENT>if timeelapsed > maxtimeout:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout,<EOL>repr(inputparams),<EOL>status_url))<EOL>return None<EOL><DEDENT>try:<EOL><INDENT>resreq = requests.get(status_url,<EOL>timeout=timeout)<EOL>resreq.raise_for_status()<EOL>resxml = parseString(resreq.text)<EOL>jobstatuselem = (<EOL>resxml.getElementsByTagName(phasekeyword)[<NUM_LIT:0>]<EOL>)<EOL>jobstatus = jobstatuselem.firstChild.toxml()<EOL>if jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>waitdone = True<EOL><DEDENT>elif jobstatus != '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (timeelapsed, jobstatus, status_url))<EOL><DEDENT>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(status_url,<EOL>resreq.text))<EOL>os.remove(incomplete_qpklf)<EOL>return None<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), status_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>status_url,<EOL>resreq.text)<EOL>)<EOL>os.remove(incomplete_qpklf)<EOL>return None<EOL><DEDENT><DEDENT>LOGINFO('<STR_LIT>')<EOL>result_url_elem = resxml.getElementsByTagName(resultkeyword)[<NUM_LIT:0>]<EOL>result_url = result_url_elem.getAttribute('<STR_LIT>')<EOL>result_nrows = result_url_elem.getAttribute('<STR_LIT>')<EOL>try:<EOL><INDENT>resreq = requests.get(result_url, timeout=timeout)<EOL>resreq.raise_for_status()<EOL>if cachefname.endswith('<STR_LIT>'):<EOL><INDENT>with gzip.open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>with open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % result_nrows)<EOL><DEDENT>tablefname = cachefname<EOL>provenance = '<STR_LIT>'<EOL>resdict = {'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT:result>':tablefname}<EOL>os.remove(incomplete_qpklf)<EOL>return resdict<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), result_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>result_url,<EOL>resreq.status_code)<EOL>)<EOL>os.remove(incomplete_qpklf)<EOL>return None<EOL><DEDENT><DEDENT>if forcefetch or (not os.path.exists(cachefname)):<EOL><INDENT>provenance = '<STR_LIT>'<EOL>jobid = '<STR_LIT>' % time.time()<EOL>inputparams['<STR_LIT>'] = jobid<EOL>inputparams['<STR_LIT>'] = '<STR_LIT>'<EOL>try:<EOL><INDENT>waitdone = False<EOL>timeelapsed = <NUM_LIT:0.0><EOL>if gaia_mirror is not None and gaia_mirror in GAIA_URLS:<EOL><INDENT>tapurl = GAIA_URLS[gaia_mirror]['<STR_LIT:url>']<EOL>resultkeyword = GAIA_URLS[gaia_mirror]['<STR_LIT>']<EOL>phasekeyword = GAIA_URLS[gaia_mirror]['<STR_LIT>']<EOL>randkey = gaia_mirror<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=GAIA_URLS[gaia_mirror]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>randkey = random.choice(list(GAIA_URLS.keys()))<EOL>tapurl = GAIA_URLS[randkey]['<STR_LIT:url>']<EOL>resultkeyword = GAIA_URLS[randkey]['<STR_LIT>']<EOL>phasekeyword = GAIA_URLS[randkey]['<STR_LIT>']<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=GAIA_URLS[randkey]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % tapurl)<EOL><DEDENT><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>% repr(inputparams))<EOL><DEDENT>mirrorok = False<EOL>ntries = <NUM_LIT:1><EOL>while not mirrorok:<EOL><INDENT>if ntries > maxtries:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>maxtries)<EOL>return None<EOL><DEDENT>try:<EOL><INDENT>req = requests.post(tapurl,<EOL>data=inputparams,<EOL>timeout=timeout)<EOL>resp_status = req.status_code<EOL>req.raise_for_status()<EOL>mirrorok = True<EOL><DEDENT>except requests.exceptions.HTTPError as e:<EOL><INDENT>LOGWARNING(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% tapurl<EOL>)<EOL>mirrorok = False<EOL>remainingmirrors = list(GAIA_URLS.keys())<EOL>remainingmirrors.remove(randkey)<EOL>randkey = random.choice(remainingmirrors)<EOL>tapurl = GAIA_URLS[randkey]['<STR_LIT:url>']<EOL>resultkeyword = GAIA_URLS[randkey]['<STR_LIT>']<EOL>phasekeyword = GAIA_URLS[randkey]['<STR_LIT>']<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=GAIA_URLS[randkey]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGWARNING(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL>mirrorok = False<EOL>remainingmirrors = list(GAIA_URLS.keys())<EOL>remainingmirrors.remove(randkey)<EOL>randkey = random.choice(remainingmirrors)<EOL>tapurl = GAIA_URLS[randkey]['<STR_LIT:url>']<EOL>resultkeyword = GAIA_URLS[randkey]['<STR_LIT>']<EOL>phasekeyword = GAIA_URLS[randkey]['<STR_LIT>']<EOL>if '<STR_LIT>' in querystr:<EOL><INDENT>inputparams['<STR_LIT>'] = (<EOL>querystr.format(<EOL>table=GAIA_URLS[randkey]['<STR_LIT>']<EOL>)<EOL>)<EOL><DEDENT><DEDENT>ntries = ntries + <NUM_LIT:1><EOL><DEDENT>status_url = req.url<EOL>resxml = parseString(req.text)<EOL>jobstatuselem = resxml.getElementsByTagName(phasekeyword)<EOL>if jobstatuselem:<EOL><INDENT>jobstatuselem = jobstatuselem[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' % phasekeyword)<EOL>LOGERROR('<STR_LIT:%s>' % req.txt)<EOL>req.close()<EOL>return None<EOL><DEDENT>jobstatus = jobstatuselem.firstChild.toxml()<EOL>if jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>waitdone = True<EOL><DEDENT><DEDENT>elif jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGERROR(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>status_url,<EOL>req.text)<EOL>)<EOL>return None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % jobstatus<EOL>)<EOL><DEDENT>while not waitdone:<EOL><INDENT>if timeelapsed > maxtimeout:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout,<EOL>repr(inputparams),<EOL>status_url,<EOL>jobstatus))<EOL>if complete_query_later and jobstatus in ('<STR_LIT>',<EOL>'<STR_LIT>'):<EOL><INDENT>incomplete_qpklf = os.path.join(<EOL>cachedir,<EOL>'<STR_LIT>' % cachekey<EOL>)<EOL>with open(incomplete_qpklf, '<STR_LIT:wb>') as outfd:<EOL><INDENT>savedict = inputparams.copy()<EOL>savedict['<STR_LIT>'] = status_url<EOL>savedict['<STR_LIT>'] = jobstatus<EOL>savedict['<STR_LIT>'] = gaia_mirror<EOL>savedict['<STR_LIT>'] = phasekeyword<EOL>savedict['<STR_LIT>'] = resultkeyword<EOL>pickle.dump(savedict,<EOL>outfd,<EOL>pickle.HIGHEST_PROTOCOL)<EOL><DEDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>jobstatus)<EOL><DEDENT>return None<EOL><DEDENT>time.sleep(refresh)<EOL>timeelapsed = timeelapsed + refresh<EOL>try:<EOL><INDENT>resreq = requests.get(status_url, timeout=timeout)<EOL>resreq.raise_for_status()<EOL>resxml = parseString(resreq.text)<EOL>jobstatuselem = (<EOL>resxml.getElementsByTagName(phasekeyword)[<NUM_LIT:0>]<EOL>)<EOL>jobstatus = jobstatuselem.firstChild.toxml()<EOL>if jobstatus == '<STR_LIT>':<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>waitdone = True<EOL><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (timeelapsed, jobstatus, status_url))<EOL><DEDENT>continue<EOL><DEDENT><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), status_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>status_url,<EOL>resreq.text)<EOL>)<EOL>return None<EOL><DEDENT><DEDENT><DEDENT>result_url_elem = resxml.getElementsByTagName(resultkeyword)[<NUM_LIT:0>]<EOL>result_url = result_url_elem.getAttribute('<STR_LIT>')<EOL>result_nrows = result_url_elem.getAttribute('<STR_LIT>')<EOL>try:<EOL><INDENT>resreq = requests.get(result_url, timeout=timeout)<EOL>resreq.raise_for_status()<EOL>if cachefname.endswith('<STR_LIT>'):<EOL><INDENT>with gzip.open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>with open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>for chunk in resreq.iter_content(chunk_size=<NUM_LIT>):<EOL><INDENT>outfd.write(chunk)<EOL><DEDENT><DEDENT><DEDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % result_nrows)<EOL><DEDENT>tablefname = cachefname<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams), result_url)<EOL>)<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams),<EOL>result_url,<EOL>resreq.status_code)<EOL>)<EOL>return None<EOL><DEDENT><DEDENT>except requests.exceptions.HTTPError as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT>' % (resp_status,<EOL>repr(inputparams)))<EOL>return None<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT:%s>' % repr(inputparams))<EOL>if '<STR_LIT>' in locals():<EOL><INDENT>LOGERROR('<STR_LIT>' % req.text)<EOL><DEDENT>return None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(inputparams)))<EOL><DEDENT>tablefname = cachefname<EOL><DEDENT>resdict = {'<STR_LIT>':inputparams,<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT:result>':tablefname}<EOL>return resdict<EOL>

This queries the GAIA TAP service using an ADQL query string.

    Parameters
    ----------

    querystr : str
        This is the ADQL query string. See:
        http://www.ivoa.net/documents/ADQL/2.0 for the specification and
        http://gea.esac.esa.int/archive-help/adql/index.html for GAIA-specific
        additions.

    gaia_mirror : {'gaia','heidelberg','vizier'} or None
        This is the key used to select a GAIA catalog mirror from the
        `GAIA_URLS` dict above. If set, the specified mirror will be used. If
        None, a random mirror chosen from that dict will be used.

    returnformat : {'csv','votable','json'}
        The returned file format to request from the GAIA catalog service.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    completequerylater : bool
        If set to True, a submitted query that does not return a result before
        `maxtimeout` has passed will be cancelled but its input request
        parameters and the result URL provided by the service will be saved. If
        this function is then called later with these same input request
        parameters, it will check if the query finally finished and a result is
        available. If so, will download the results instead of submitting a new
        query. If it's not done yet, will start waiting for results again. To
        force launch a new query with the same request parameters, set the
        `forcefetch` kwarg to True.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


<EOL>query = (<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>)<EOL>if extra_filter is not None:<EOL><INDENT>extra_filter_str = '<STR_LIT>' % extra_filter<EOL><DEDENT>else:<EOL><INDENT>extra_filter_str = '<STR_LIT>'<EOL><DEDENT>formatted_query = query.format(ra_center=racenter,<EOL>decl_center=declcenter,<EOL>search_radius=searchradiusarcsec/<NUM_LIT>,<EOL>extra_filter_str=extra_filter_str,<EOL>columns='<STR_LIT:U+002CU+0020>'.join(columns))<EOL>return tap_query(formatted_query,<EOL>gaia_mirror=gaia_mirror,<EOL>returnformat=returnformat,<EOL>forcefetch=forcefetch,<EOL>cachedir=cachedir,<EOL>verbose=verbose,<EOL>timeout=timeout,<EOL>refresh=refresh,<EOL>maxtimeout=maxtimeout,<EOL>maxtries=maxtries,<EOL>complete_query_later=complete_query_later)<EOL>

This queries the GAIA TAP service for a list of objects near the coords.

    Runs a conesearch around `(racenter, declcenter)` with radius in arcsec of
    `searchradiusarcsec`.

    Parameters
    ----------

    racenter,declcenter : float
        The center equatorial coordinates in decimal degrees.

    searchradiusarcsec : float
        The search radius of the cone-search in arcseconds.

    gaia_mirror : {'gaia','heidelberg','vizier'} or None
        This is the key used to select a GAIA catalog mirror from the
        `GAIA_URLS` dict above. If set, the specified mirror will be used. If
        None, a random mirror chosen from that dict will be used.

    columns : sequence of str
        This indicates which columns from the GAIA table to request for the
        objects found within the search radius.

    extra_filter: str or None
        If this is provided, must be a valid ADQL filter string that is used to
        further filter the cone-search results.

    returnformat : {'csv','votable','json'}
        The returned file format to request from the GAIA catalog service.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    completequerylater : bool
        If set to True, a submitted query that does not return a result before
        `maxtimeout` has passed will be cancelled but its input request
        parameters and the result URL provided by the service will be saved. If
        this function is then called later with these same input request
        parameters, it will check if the query finally finished and a result is
        available. If so, will download the results instead of submitting a new
        query. If it's not done yet, will start waiting for results again. To
        force launch a new query with the same request parameters, set the
        `forcefetch` kwarg to True.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


<EOL>query = (<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>)<EOL>ra_min, ra_max, decl_min, decl_max = radeclbox<EOL>ra_center = (ra_max + ra_min)/<NUM_LIT><EOL>decl_center = (decl_max + decl_min)/<NUM_LIT><EOL>ra_width = ra_max - ra_min<EOL>decl_height = decl_max - decl_min<EOL>if extra_filter is not None:<EOL><INDENT>extra_filter_str = '<STR_LIT>' % extra_filter<EOL><DEDENT>else:<EOL><INDENT>extra_filter_str = '<STR_LIT>'<EOL><DEDENT>formatted_query = query.format(columns='<STR_LIT:U+002CU+0020>'.join(columns),<EOL>extra_filter_str=extra_filter_str,<EOL>ra_center=ra_center,<EOL>decl_center=decl_center,<EOL>ra_width=ra_width,<EOL>decl_height=decl_height)<EOL>return tap_query(formatted_query,<EOL>gaia_mirror=gaia_mirror,<EOL>returnformat=returnformat,<EOL>forcefetch=forcefetch,<EOL>cachedir=cachedir,<EOL>verbose=verbose,<EOL>timeout=timeout,<EOL>refresh=refresh,<EOL>maxtimeout=maxtimeout,<EOL>maxtries=maxtries,<EOL>complete_query_later=complete_query_later)<EOL>

This queries the GAIA TAP service for a list of objects in an equatorial
    coordinate box.

    Parameters
    ----------

    radeclbox : sequence of four floats
        This defines the box to search in::

            [ra_min, ra_max, decl_min, decl_max]

    gaia_mirror : {'gaia','heidelberg','vizier'} or None
        This is the key used to select a GAIA catalog mirror from the
        `GAIA_URLS` dict above. If set, the specified mirror will be used. If
        None, a random mirror chosen from that dict will be used.

    columns : sequence of str
        This indicates which columns from the GAIA table to request for the
        objects found within the search radius.

    extra_filter: str or None
        If this is provided, must be a valid ADQL filter string that is used to
        further filter the cone-search results.

    returnformat : {'csv','votable','json'}
        The returned file format to request from the GAIA catalog service.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    completequerylater : bool
        If set to True, a submitted query that does not return a result before
        `maxtimeout` has passed will be cancelled but its input request
        parameters and the result URL provided by the service will be saved. If
        this function is then called later with these same input request
        parameters, it will check if the query finally finished and a result is
        available. If so, will download the results instead of submitting a new
        query. If it's not done yet, will start waiting for results again. To
        force launch a new query with the same request parameters, set the
        `forcefetch` kwarg to True.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


This queries the GAIA TAP service for a single GAIA source ID.

    Parameters
    ----------

    gaiaid : str
        The source ID of the object whose info will be collected.

    gaia_mirror : {'gaia','heidelberg','vizier'} or None
        This is the key used to select a GAIA catalog mirror from the
        `GAIA_URLS` dict above. If set, the specified mirror will be used. If
        None, a random mirror chosen from that dict will be used.

    columns : sequence of str
        This indicates which columns from the GAIA table to request for the
        objects found within the search radius.

    returnformat : {'csv','votable','json'}
        The returned file format to request from the GAIA catalog service.

    forcefetch : bool
        If this is True, the query will be retried even if cached results for
        it exist.

    cachedir : str
        This points to the directory where results will be downloaded.

    verbose : bool
        If True, will indicate progress and warn of any issues.

    timeout : float
        This sets the amount of time in seconds to wait for the service to
        respond to our initial request.

    refresh : float
        This sets the amount of time in seconds to wait before checking if the
        result file is available. If the results file isn't available after
        `refresh` seconds have elapsed, the function will wait for `refresh`
        seconds continuously, until `maxtimeout` is reached or the results file
        becomes available.

    maxtimeout : float
        The maximum amount of time in seconds to wait for a result to become
        available after submitting our query request.

    maxtries : int
        The maximum number of tries (across all mirrors tried) to make to either
        submit the request or download the results, before giving up.

    completequerylater : bool
        If set to True, a submitted query that does not return a result before
        `maxtimeout` has passed will be cancelled but its input request
        parameters and the result URL provided by the service will be saved. If
        this function is then called later with these same input request
        parameters, it will check if the query finally finished and a result is
        available. If so, will download the results instead of submitting a new
        query. If it's not done yet, will start waiting for results again. To
        force launch a new query with the same request parameters, set the
        `forcefetch` kwarg to True.

    Returns
    -------

    dict
        This returns a dict of the following form::

            {'params':dict of the input params used for the query,
             'provenance':'cache' or 'new download',
             'result':path to the file on disk with the downloaded data table}


<EOL>formposition = ['<STR_LIT>' % (ra, decl)]<EOL>formscaling = [scaling]<EOL>formparams = copy.deepcopy(SKYVIEW_PARAMS)<EOL>formparams['<STR_LIT>'] = formposition<EOL>formparams['<STR_LIT>'][<NUM_LIT:0>] = survey<EOL>formparams['<STR_LIT>'] = formscaling<EOL>formparams['<STR_LIT>'] = ['<STR_LIT:%s>' % sizepix]<EOL>if '<STR_LIT>' in cachedir:<EOL><INDENT>cachedir = os.path.expanduser(cachedir)<EOL><DEDENT>if not os.path.exists(cachedir):<EOL><INDENT>os.makedirs(cachedir)<EOL><DEDENT>cachekey = '<STR_LIT>' % (formposition[<NUM_LIT:0>], survey, scaling, sizepix)<EOL>cachekey = hashlib.sha256(cachekey.encode()).hexdigest()<EOL>cachefname = os.path.join(cachedir, '<STR_LIT>' % cachekey)<EOL>provenance = '<STR_LIT>'<EOL>if sizepix == <NUM_LIT>:<EOL><INDENT>oldcachekey = '<STR_LIT>' % (formposition[<NUM_LIT:0>], survey, scaling)<EOL>oldcachekey = hashlib.sha256(oldcachekey.encode()).hexdigest()<EOL>oldcachefname = os.path.join(cachedir, '<STR_LIT>' % oldcachekey)<EOL>if os.path.exists(oldcachefname):<EOL><INDENT>cachefname = oldcachefname<EOL><DEDENT><DEDENT>if forcefetch or (not os.path.exists(cachefname)):<EOL><INDENT>provenance = '<STR_LIT>'<EOL>time.sleep(random.randint(<NUM_LIT:1>,jitter))<EOL>try:<EOL><INDENT>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % (<EOL>formposition[<NUM_LIT:0>],<EOL>survey,<EOL>scaling,<EOL>sizepix)<EOL>)<EOL><DEDENT>req = requests.get(SKYVIEW_URL, params=formparams, timeout=timeout)<EOL>req.raise_for_status()<EOL>resp = req.text<EOL>fitsurls = FITS_REGEX.findall(resp)<EOL>if fitsurls:<EOL><INDENT>for fitsurl in fitsurls:<EOL><INDENT>fullfitsurl = urljoin(FITS_BASEURL, fitsurl)<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>' % fullfitsurl)<EOL><DEDENT>fitsreq = requests.get(fullfitsurl, timeout=timeout)<EOL>with gzip.open(cachefname,'<STR_LIT:wb>') as outfd:<EOL><INDENT>outfd.write(fitsreq.content)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>formposition)<EOL>return None<EOL><DEDENT><DEDENT>except requests.exceptions.HTTPError as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT>' % repr(formposition))<EOL>return None<EOL><DEDENT>except requests.exceptions.Timeout as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(repr(formposition), timeout))<EOL>return None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>'<EOL>'<STR_LIT>' % repr(formposition))<EOL>return None<EOL><DEDENT><DEDENT>try:<EOL><INDENT>stampfits = pyfits.open(cachefname)<EOL>stampfits.close()<EOL>retdict = {<EOL>'<STR_LIT>':{'<STR_LIT>':ra,<EOL>'<STR_LIT>':decl,<EOL>'<STR_LIT>':survey,<EOL>'<STR_LIT>':scaling,<EOL>'<STR_LIT>':sizepix},<EOL>'<STR_LIT>':provenance,<EOL>'<STR_LIT>':cachefname<EOL>}<EOL>return retdict<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>{'<STR_LIT>':ra,<EOL>'<STR_LIT>':decl,<EOL>'<STR_LIT>':survey,<EOL>'<STR_LIT>': scaling,<EOL>'<STR_LIT>': sizepix})<EOL>if retry_failed:<EOL><INDENT>return get_stamp(ra, decl,<EOL>survey=survey,<EOL>scaling=scaling,<EOL>sizepix=sizepix,<EOL>forcefetch=True,<EOL>cachedir=cachedir,<EOL>timeout=timeout,<EOL>verbose=verbose)<EOL><DEDENT>else:<EOL><INDENT>return None<EOL><DEDENT><DEDENT>

This gets a FITS cutout from the NASA GSFC SkyView service.

    This downloads stamps in FITS format from the NASA SkyView service:

    https://skyview.gsfc.nasa.gov/current/cgi/query.pl

    Parameters
    ----------

    ra,decl : float
        These are decimal equatorial coordinates for the cutout center.

    survey : str
        The survey name to get the stamp from. This is one of the
        values in the 'SkyView Surveys' option boxes on the SkyView
        webpage. Currently, we've only tested using 'DSS2 Red' as the value for
        this kwarg, but the other ones should work in principle.

    scaling : str
        This is the pixel value scaling function to use.

    sizepix : int
        The width and height of the cutout are specified by this value.

    forcefetch : bool
        If True, will disregard any existing cached copies of the stamp already
        downloaded corresponding to the requested center coordinates and
        redownload the FITS from the SkyView service.

    cachedir : str
        This is the path to the astrobase cache directory. All downloaded FITS
        stamps are stored here as .fits.gz files so we can immediately respond
        with the cached copy when a request is made for a coordinate center
        that's already been downloaded.

    timeout : float
        Sets the timeout in seconds to wait for a response from the NASA SkyView
        service.

    retry_failed : bool
        If the initial request to SkyView fails, and this is True, will retry
        until it succeeds.

    verbose : bool
        If True, indicates progress.

    jitter : float
        This is used to control the scale of the random wait in seconds before
        starting the query. Useful in parallelized situations.

    Returns
    -------

    dict
        A dict of the following form is returned::

            {
                'params':{input ra, decl and kwargs used},
                'provenance':'cached' or 'new download',
                'fitsfile':FITS file to which the cutout was saved on disk
            }


USERHOME = os.path.expanduser('<STR_LIT>')<EOL>APIKEYFILE = os.path.join(USERHOME,<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>'<STR_LIT>' % lcc_server.replace(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'<EOL>).replace(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'<EOL>))<EOL>if os.path.exists(APIKEYFILE):<EOL><INDENT>fileperm = oct(os.stat(APIKEYFILE)[stat.ST_MODE])<EOL>if fileperm == '<STR_LIT>' or fileperm == '<STR_LIT>':<EOL><INDENT>with open(APIKEYFILE) as infd:<EOL><INDENT>apikey, expires = infd.read().strip('<STR_LIT:\n>').split()<EOL><DEDENT>now = datetime.now(utc)<EOL>if sys.version_info[:<NUM_LIT:2>] < (<NUM_LIT:3>,<NUM_LIT:7>):<EOL><INDENT>expdt = datetime.strptime(<EOL>expires.replace('<STR_LIT>','<STR_LIT>'),<EOL>'<STR_LIT>'<EOL>).replace(tzinfo=utc)<EOL><DEDENT>else:<EOL><INDENT>expdt = datetime.fromisoformat(expires.replace('<STR_LIT>','<STR_LIT>'))<EOL><DEDENT>if now > expdt:<EOL><INDENT>LOGERROR('<STR_LIT>' % expires)<EOL>return False, apikey, expires<EOL><DEDENT>else:<EOL><INDENT>return True, apikey, expires<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% APIKEYFILE)<EOL>return False, None, None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'.format(apikeyfile=APIKEYFILE))<EOL>return False, None, None<EOL><DEDENT>

This validates if an API key for the specified LCC-Server is available.

    API keys are stored using the following file scheme::

        ~/.astrobase/lccs/apikey-domain.of.lccserver.org

    e.g. for the HAT LCC-Server at https://data.hatsurveys.org::

        ~/.astrobase/lccs/apikey-https-data.hatsurveys.org

    Parameters
    ----------

    lcc_server : str
        The base URL of the LCC-Server for which the existence of API keys will
        be checked.

    Returns
    -------

    (apikey_ok, apikey_str, expiry) : tuple
        The returned tuple contains the status of the API key, the API key
        itself if present, and its expiry date if present.


USERHOME = os.path.expanduser('<STR_LIT>')<EOL>APIKEYFILE = os.path.join(USERHOME,<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>'<STR_LIT>' % lcc_server.replace(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'<EOL>).replace(<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'<EOL>))<EOL>url = '<STR_LIT>' % lcc_server<EOL>resp = urlopen(url)<EOL>if resp.code == <NUM_LIT:200>:<EOL><INDENT>respdict = json.loads(resp.read())<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>lcc_server)<EOL>LOGERROR('<STR_LIT>' % resp.status_code)<EOL>return None<EOL><DEDENT>apikey = respdict['<STR_LIT:result>']['<STR_LIT>']<EOL>expires = respdict['<STR_LIT:result>']['<STR_LIT>']<EOL>if not os.path.exists(os.path.dirname(APIKEYFILE)):<EOL><INDENT>os.makedirs(os.path.dirname(APIKEYFILE))<EOL><DEDENT>with open(APIKEYFILE,'<STR_LIT:w>') as outfd:<EOL><INDENT>outfd.write('<STR_LIT>' % (apikey, expires))<EOL><DEDENT>os.chmod(APIKEYFILE, <NUM_LIT>)<EOL>LOGINFO('<STR_LIT>' % (lcc_server,<EOL>expires))<EOL>LOGINFO('<STR_LIT>' % APIKEYFILE)<EOL>return apikey, expires<EOL>

This gets a new API key from the specified LCC-Server.

    NOTE: this only gets an anonymous API key. To get an API key tied to a user
    account (and associated privilege level), see the `import_apikey` function
    below.

    Parameters
    ----------

    lcc_server : str
        The base URL of the LCC-Server from where the API key will be fetched.

    Returns
    -------

    (apikey, expiry) : tuple
        This returns a tuple with the API key and its expiry date.