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>respdict = json.loads(apikey_text_json)<EOL>apikey = respdict['<STR_LIT>']<EOL>expires = respdict['<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 imports an API key from text and writes it to the cache dir.

    Use this with the JSON text copied from the API key text box on your
    LCC-Server user home page. The API key will thus be tied to the privileges
    of that user account and can then access objects, datasets, and collections
    marked as private for the user only or shared with that user.

    Parameters
    ----------

    lcc_server : str
        The base URL of the LCC-Server to get the API key for.

    apikey_text_json : str
        The JSON string from the API key text box on the user's LCC-Server home
        page at `lcc_server/users/home`.

    Returns
    -------

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


def submit_post_searchquery(url, data, apikey):

<EOL>postdata = {}<EOL>for key in data:<EOL><INDENT>if key == '<STR_LIT>':<EOL><INDENT>postdata['<STR_LIT>'] = data[key]<EOL><DEDENT>elif key == '<STR_LIT>':<EOL><INDENT>postdata['<STR_LIT>'] = data[key]<EOL><DEDENT>else:<EOL><INDENT>postdata[key] = data[key]<EOL><DEDENT><DEDENT>encoded_postdata = urlencode(postdata, doseq=True).encode()<EOL>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>LOGINFO('<STR_LIT>' % url)<EOL>try:<EOL><INDENT>req = Request(url, data=encoded_postdata, headers=headers)<EOL>resp = urlopen(req)<EOL>if resp.code == <NUM_LIT:200>:<EOL><INDENT>for line in resp:<EOL><INDENT>data = json.loads(line)<EOL>msg = data['<STR_LIT:message>']<EOL>status = data['<STR_LIT:status>']<EOL>if status != '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>' % (status, msg))<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>' % (status, msg))<EOL><DEDENT>if status in ('<STR_LIT>','<STR_LIT>'):<EOL><INDENT>setid = data['<STR_LIT:result>']['<STR_LIT>']<EOL>outpickle = os.path.join(os.path.expanduser('<STR_LIT>'),<EOL>'<STR_LIT>',<EOL>'<STR_LIT>',<EOL>'<STR_LIT>' % setid)<EOL>if not os.path.exists(os.path.dirname(outpickle)):<EOL><INDENT>os.makedirs(os.path.dirname(outpickle))<EOL><DEDENT>with open(outpickle,'<STR_LIT:wb>') as outfd:<EOL><INDENT>pickle.dump(data, outfd, pickle.HIGHEST_PROTOCOL)<EOL>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % outpickle)<EOL><DEDENT>return status, data, data['<STR_LIT:result>']['<STR_LIT>']<EOL><DEDENT>elif status == '<STR_LIT>':<EOL><INDENT>return status, data, None<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>try:<EOL><INDENT>data = json.load(resp)<EOL>msg = data['<STR_LIT:message>']<EOL>LOGERROR(msg)<EOL>return '<STR_LIT>', None, None<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>' % url)<EOL>return '<STR_LIT>', None, None<EOL><DEDENT><DEDENT><DEDENT>except HTTPError as e:<EOL><INDENT>LOGERROR('<STR_LIT>' % url)<EOL>LOGERROR('<STR_LIT>' % (e.code, e.reason))<EOL>return '<STR_LIT>', None, None<EOL><DEDENT>

This submits a POST query to an LCC-Server search API endpoint.

    Handles streaming of the results, and returns the final JSON stream. Also
    handles results that time out.

    Parameters
    ----------

    url : str
        The URL of the search API endpoint to hit. This is something like
        `https://data.hatsurveys.org/api/conesearch`

    data : dict
        A dict of the search query parameters to pass to the search service.

    apikey : str
        The API key to use to access the search service. API keys are required
        for all POST request made to an LCC-Server's API endpoints.

    Returns
    -------

    (status_flag, data_dict, dataset_id) : tuple
        This returns a tuple containing the status of the request: ('complete',
        'failed', 'background', etc.), a dict parsed from the JSON result of the
        request, and a dataset ID, which can be used to reconstruct the URL on
        the LCC-Server where the results can be browsed.


<EOL>if isinstance(searchresult, tuple):<EOL><INDENT>info, setid = searchresult[<NUM_LIT:1>:]<EOL><DEDENT>elif isinstance(searchresult, str) and os.path.exists(searchresult):<EOL><INDENT>with open(searchresult,'<STR_LIT:rb>') as infd:<EOL><INDENT>info = pickle.load(infd)<EOL><DEDENT>setid = info['<STR_LIT:result>']['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>return None, None, None<EOL><DEDENT>dataset_pickle = '<STR_LIT>' % setid<EOL>dataset_csv = '<STR_LIT>' % setid<EOL>dataset_lczip = '<STR_LIT>' % setid<EOL>if outdir is None:<EOL><INDENT>localdir = os.getcwd()<EOL><DEDENT>else:<EOL><INDENT>localdir = outdir<EOL><DEDENT>server_scheme, server_netloc = urlparse(info['<STR_LIT:result>']['<STR_LIT>'])[:<NUM_LIT:2>]<EOL>dataset_pickle_link = '<STR_LIT>' % (server_scheme,<EOL>server_netloc,<EOL>dataset_pickle)<EOL>dataset_csv_link = '<STR_LIT>' % (server_scheme,<EOL>server_netloc,<EOL>dataset_csv)<EOL>dataset_lczip_link = '<STR_LIT>' % (server_scheme,<EOL>server_netloc,<EOL>dataset_lczip)<EOL>if getpickle:<EOL><INDENT>LOGINFO('<STR_LIT>' % dataset_pickle_link)<EOL>try:<EOL><INDENT>if os.path.exists(os.path.join(localdir, dataset_pickle)):<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>local_dataset_pickle = os.path.join(localdir,<EOL>dataset_pickle)<EOL><DEDENT>else:<EOL><INDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(<EOL>dataset_pickle_link,<EOL>data=None,<EOL>headers=headers<EOL>)<EOL>resp = urlopen(req)<EOL>LOGINFO('<STR_LIT>' % dataset_pickle)<EOL>localf = os.path.join(localdir, dataset_pickle)<EOL>with open(localf, '<STR_LIT:wb>') as outfd:<EOL><INDENT>with resp:<EOL><INDENT>data = resp.read()<EOL>outfd.write(data)<EOL><DEDENT><DEDENT>LOGINFO('<STR_LIT>' % localf)<EOL>local_dataset_pickle = localf<EOL><DEDENT><DEDENT>except HTTPError as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(dataset_pickle_link, e.code, e.reason))<EOL>local_dataset_pickle = None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>local_dataset_pickle = None<EOL><DEDENT>LOGINFO('<STR_LIT>' % dataset_csv_link)<EOL>try:<EOL><INDENT>if os.path.exists(os.path.join(localdir, dataset_csv)):<EOL><INDENT>LOGWARNING('<STR_LIT>')<EOL>local_dataset_csv = os.path.join(localdir, dataset_csv)<EOL><DEDENT>else:<EOL><INDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(<EOL>dataset_csv_link,<EOL>data=None,<EOL>headers=headers<EOL>)<EOL>resp = urlopen(req)<EOL>LOGINFO('<STR_LIT>' % dataset_csv)<EOL>localf = os.path.join(localdir, dataset_csv)<EOL>with open(localf, '<STR_LIT:wb>') as outfd:<EOL><INDENT>with resp:<EOL><INDENT>data = resp.read()<EOL>outfd.write(data)<EOL><DEDENT><DEDENT>LOGINFO('<STR_LIT>' % localf)<EOL>local_dataset_csv = localf<EOL><DEDENT><DEDENT>except HTTPError as e:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>(dataset_csv_link, e.code, e.reason))<EOL>local_dataset_csv = None<EOL><DEDENT>LOGINFO('<STR_LIT>' % dataset_lczip_link)<EOL>try:<EOL><INDENT>if os.path.exists(os.path.join(localdir, dataset_lczip)):<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>local_dataset_lczip = os.path.join(localdir, dataset_lczip)<EOL><DEDENT>else:<EOL><INDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(<EOL>dataset_lczip_link,<EOL>data=None,<EOL>headers=headers<EOL>)<EOL>resp = urlopen(req)<EOL>LOGINFO('<STR_LIT>' % dataset_lczip)<EOL>localf = os.path.join(localdir, dataset_lczip)<EOL>with open(localf, '<STR_LIT:wb>') as outfd:<EOL><INDENT>with resp:<EOL><INDENT>data = resp.read()<EOL>outfd.write(data)<EOL><DEDENT><DEDENT>LOGINFO('<STR_LIT>' % localf)<EOL>local_dataset_lczip = localf<EOL><DEDENT><DEDENT>except HTTPError as e:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>(dataset_lczip_link, e.code, e.reason))<EOL>local_dataset_lczip = None<EOL><DEDENT>return local_dataset_csv, local_dataset_lczip, local_dataset_pickle<EOL>

This retrieves a search result dataset's CSV and any LC zip files.

    Takes the output from the `submit_post_searchquery` function above or a
    pickle file generated from that function's output if the query timed out.

    Parameters
    ----------

    searchresult : str or tuple
        If provided as a str, points to the pickle file created using the output
        from the `submit_post_searchquery` function. If provided as a tuple,
        this is the result tuple from the `submit_post_searchquery` function.

    getpickle : False
        If this is True, will also download the dataset's pickle. Note that
        LCC-Server is a Python 3.6+ package (while lccs.py still works with
        Python 2.7) and it saves its pickles in pickle.HIGHEST_PROTOCOL for
        efficiency, so these pickles may be unreadable in lower Pythons. As an
        alternative, the dataset CSV contains the full data table and all the
        information about the dataset in its header, which is JSON
        parseable. You can also use the function `get_dataset` below to get the
        dataset pickle information in JSON form.

    outdir : None or str
        If this is a str, points to the output directory where the results will
        be placed. If it's None, they will be placed in the current directory.

    apikey : str or None
        If this is a str, uses the given API key to authenticate the download
        request. This is useful when you have a private dataset you want to get
        products for.

    Returns
    -------

    (local_dataset_csv, local_dataset_lczip, local_dataset_pickle) : tuple
        This returns a tuple containing paths to the dataset CSV, LC zipfile,
        and the dataset pickle if getpickle was set to True (None otherwise).


<EOL>coords = '<STR_LIT>' % (center_ra, center_decl, radiusarcmin)<EOL>params = {<EOL>'<STR_LIT>':coords<EOL>}<EOL>if collections:<EOL><INDENT>params['<STR_LIT>'] = collections<EOL><DEDENT>if columns:<EOL><INDENT>params['<STR_LIT>'] = columns<EOL><DEDENT>if filters:<EOL><INDENT>params['<STR_LIT>'] = filters<EOL><DEDENT>if sortspec:<EOL><INDENT>params['<STR_LIT>'] = json.dumps([sortspec])<EOL><DEDENT>if samplespec:<EOL><INDENT>params['<STR_LIT>'] = int(samplespec)<EOL><DEDENT>if limitspec:<EOL><INDENT>params['<STR_LIT>'] = int(limitspec)<EOL><DEDENT>params['<STR_LIT>'] = result_visibility<EOL>params['<STR_LIT>'] = email_when_done<EOL>if email_when_done:<EOL><INDENT>download_data = False<EOL><DEDENT>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>api_url = '<STR_LIT>' % lcc_server<EOL>searchresult = submit_post_searchquery(api_url, params, apikey)<EOL>status = searchresult[<NUM_LIT:0>]<EOL>if download_data:<EOL><INDENT>if status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if pkl:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip, pkl<EOL><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT><DEDENT>elif status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout/<NUM_LIT>, refresh))<EOL>timewaited = <NUM_LIT:0.0><EOL>while timewaited < maxtimeout:<EOL><INDENT>try:<EOL><INDENT>time.sleep(refresh)<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if (csv and os.path.exists(csv) and<EOL>lczip and os.path.exists(lczip)):<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT>timewaited = timewaited + refresh<EOL><DEDENT>except KeyboardInterrupt:<EOL><INDENT>LOGWARNING('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>

This runs a cone-search query.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.  (e.g. for HAT, use:
        https://data.hatsurveys.org)

    center_ra,center_decl : float
        These are the central coordinates of the search to conduct. These can be
        either decimal degrees of type float, or sexagesimal coordinates of type
        str:

        - OK: 290.0, 45.0
        - OK: 15:00:00 +45:00:00
        - OK: 15 00 00.0 -45 00 00.0
        - NOT OK: 290.0 +45:00:00
        - NOT OK: 15:00:00 45.0

    radiusarcmin : float
        This is the search radius to use for the cone-search. This is in
        arcminutes. The maximum radius you can use is 60 arcminutes = 1 degree.

    result_visibility : {'private', 'unlisted', 'public'}
        This sets the visibility of the dataset produced from the search
        result::

               'private' -> the dataset and its products are not visible or
                            accessible by any user other than the one that
                            created the dataset.

               'unlisted' -> the dataset and its products are not visible in the
                             list of public datasets, but can be accessed if the
                             dataset URL is known

               'public' -> the dataset and its products are visible in the list
                           of public datasets and can be accessed by anyone.

    email_when_done : bool
        If True, the LCC-Server will email you when the search is complete. This
        will also set `download_data` to False. Using this requires an
        LCC-Server account and an API key tied to that account.

    collections : list of str or None
        This is a list of LC collections to search in. If this is None, all
        collections will be searched.

    columns : list of str or None
        This is a list of columns to return in the results. Matching objects'
        object IDs, RAs, DECs, and links to light curve files will always be
        returned so there is no need to specify these columns. If None, only
        these columns will be returned: 'objectid', 'ra', 'decl', 'lcfname'

    filters : str or None
        This is an SQL-like string to use to filter on database columns in the
        LCC-Server's collections. To see the columns available for a search,
        visit the Collections tab in the LCC-Server's browser UI. The filter
        operators allowed are::

            lt      -> less than
            gt      -> greater than
            ge      -> greater than or equal to
            le      -> less than or equal to
            eq      -> equal to
            ne      -> not equal to
            ct      -> contains text
            isnull  -> column value is null
            notnull -> column value is not null

        You may use the `and` and `or` operators between filter specifications
        to chain them together logically.

        Example filter strings::

            "(propermotion gt 200.0) and (sdssr lt 11.0)"
            "(dered_jmag_kmag gt 2.0) and (aep_000_stetsonj gt 10.0)"
            "(gaia_status ct 'ok') and (propermotion gt 300.0)"
            "(simbad_best_objtype ct 'RR') and (dered_sdssu_sdssg lt 0.5)"

    sortspec : tuple of two strs or None
        If not None, this should be a tuple of two items::

            ('column to sort by', 'asc|desc')

        This sets the column to sort the results by. For cone_search, the
        default column and sort order are 'dist_arcsec' and 'asc', meaning the
        distance from the search center in ascending order.

    samplespec : int or None
        If this is an int, will indicate how many rows from the initial search
        result will be uniformly random sampled and returned.

    limitspec : int or None
        If this is an int, will indicate how many rows from the initial search
        result to return in total.

        `sortspec`, `samplespec`, and `limitspec` are applied in this order:

            sample -> sort -> limit

    download_data : bool
        This sets if the accompanying data from the search results will be
        downloaded automatically. This includes the data table CSV, the dataset
        pickle file, and a light curve ZIP file. Note that if the search service
        indicates that your query is still in progress, this function will block
        until the light curve ZIP file becomes available. The maximum wait time
        in seconds is set by maxtimeout and the refresh interval is set by
        refresh.

        To avoid the wait block, set download_data to False and the function
        will write a pickle file to `~/.astrobase/lccs/query-[setid].pkl`
        containing all the information necessary to retrieve these data files
        later when the query is done. To do so, call the
        `retrieve_dataset_files` with the path to this pickle file (it will be
        returned).

    outdir : str or None
        If this is provided, sets the output directory of the downloaded dataset
        files. If None, they will be downloaded to the current directory.

    maxtimeout : float
        The maximum time in seconds to wait for the LCC-Server to respond with a
        result before timing out. You can use the `retrieve_dataset_files`
        function to get results later as needed.

    refresh : float
        The time to wait in seconds before pinging the LCC-Server to see if a
        search query has completed and dataset result files can be downloaded.

    Returns
    -------

    tuple
        Returns a tuple with the following elements::

            (search result status dict,
             search result CSV file path,
             search result LC ZIP path)


<EOL>params = {'<STR_LIT>':searchterm}<EOL>if collections:<EOL><INDENT>params['<STR_LIT>'] = collections<EOL><DEDENT>if columns:<EOL><INDENT>params['<STR_LIT>'] = columns<EOL><DEDENT>if filters:<EOL><INDENT>params['<STR_LIT>'] = filters<EOL><DEDENT>if sortspec:<EOL><INDENT>params['<STR_LIT>'] = json.dumps([sortspec])<EOL><DEDENT>if samplespec:<EOL><INDENT>params['<STR_LIT>'] = int(samplespec)<EOL><DEDENT>if limitspec:<EOL><INDENT>params['<STR_LIT>'] = int(limitspec)<EOL><DEDENT>params['<STR_LIT>'] = result_visibility<EOL>params['<STR_LIT>'] = email_when_done<EOL>params['<STR_LIT>'] = sesame_lookup<EOL>if email_when_done:<EOL><INDENT>download_data = False<EOL><DEDENT>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>api_url = '<STR_LIT>' % lcc_server<EOL>searchresult = submit_post_searchquery(api_url, params, apikey)<EOL>status = searchresult[<NUM_LIT:0>]<EOL>if download_data:<EOL><INDENT>if status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if pkl:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip, pkl<EOL><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT><DEDENT>elif status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout/<NUM_LIT>, refresh))<EOL>timewaited = <NUM_LIT:0.0><EOL>while timewaited < maxtimeout:<EOL><INDENT>try:<EOL><INDENT>time.sleep(refresh)<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if (csv and os.path.exists(csv) and<EOL>lczip and os.path.exists(lczip)):<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT>timewaited = timewaited + refresh<EOL><DEDENT>except KeyboardInterrupt:<EOL><INDENT>LOGWARNING('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>

This runs a full-text search query.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.  (e.g. for HAT, use:
        https://data.hatsurveys.org)

    searchterm : str
        This is the term to look for in a full-text search of the LCC-Server's
        collections. This can be an object name, tag, description, etc., as
        noted in the LCC-Server's full-text search tab in its browser UI. To
        search for an exact match to a string (like an object name), you can add
        double quotes around the string, e.g. searchitem = '"exact match to me
        needed"'.

    sesame_lookup : bool
        If True, means the LCC-Server will assume the provided search term is a
        single object's name, look up its coordinates using the CDS SIMBAD
        SESAME name resolution service, and then search the LCC-Server for any
        matching objects. The object name can be either a star name known to
        SIMBAD, or it can be an extended source name (e.g. an open cluster or
        nebula). In the first case, a search radius of 5 arcseconds will be
        used. In the second case, a search radius of 1 degree will be used to
        find all nearby database objects associated with an extended source
        name.

    result_visibility : {'private', 'unlisted', 'public'}
        This sets the visibility of the dataset produced from the search
        result::

               'private' -> the dataset and its products are not visible or
                            accessible by any user other than the one that
                            created the dataset.

               'unlisted' -> the dataset and its products are not visible in the
                             list of public datasets, but can be accessed if the
                             dataset URL is known

               'public' -> the dataset and its products are visible in the list
                           of public datasets and can be accessed by anyone.

    email_when_done : bool
        If True, the LCC-Server will email you when the search is complete. This
        will also set `download_data` to False. Using this requires an
        LCC-Server account and an API key tied to that account.

    collections : list of str or None
        This is a list of LC collections to search in. If this is None, all
        collections will be searched.

    columns : list of str or None
        This is a list of columns to return in the results. Matching objects'
        object IDs, RAs, DECs, and links to light curve files will always be
        returned so there is no need to specify these columns. If None, only
        these columns will be returned: 'objectid', 'ra', 'decl', 'lcfname'

    filters : str or None
        This is an SQL-like string to use to filter on database columns in the
        LCC-Server's collections. To see the columns available for a search,
        visit the Collections tab in the LCC-Server's browser UI. The filter
        operators allowed are::

            lt      -> less than
            gt      -> greater than
            ge      -> greater than or equal to
            le      -> less than or equal to
            eq      -> equal to
            ne      -> not equal to
            ct      -> contains text
            isnull  -> column value is null
            notnull -> column value is not null

        You may use the `and` and `or` operators between filter specifications
        to chain them together logically.

        Example filter strings::

            "(propermotion gt 200.0) and (sdssr lt 11.0)"
            "(dered_jmag_kmag gt 2.0) and (aep_000_stetsonj gt 10.0)"
            "(gaia_status ct 'ok') and (propermotion gt 300.0)"
            "(simbad_best_objtype ct 'RR') and (dered_sdssu_sdssg lt 0.5)"

    sortspec : tuple of two strs or None
        If not None, this should be a tuple of two items::

            ('column to sort by', 'asc|desc')

        This sets the column to sort the results by. For cone_search, the
        default column and sort order are 'dist_arcsec' and 'asc', meaning the
        distance from the search center in ascending order.

    samplespec : int or None
        If this is an int, will indicate how many rows from the initial search
        result will be uniformly random sampled and returned.

    limitspec : int or None
        If this is an int, will indicate how many rows from the initial search
        result to return in total.

        `sortspec`, `samplespec`, and `limitspec` are applied in this order:

            sample -> sort -> limit

    download_data : bool
        This sets if the accompanying data from the search results will be
        downloaded automatically. This includes the data table CSV, the dataset
        pickle file, and a light curve ZIP file. Note that if the search service
        indicates that your query is still in progress, this function will block
        until the light curve ZIP file becomes available. The maximum wait time
        in seconds is set by maxtimeout and the refresh interval is set by
        refresh.

        To avoid the wait block, set download_data to False and the function
        will write a pickle file to `~/.astrobase/lccs/query-[setid].pkl`
        containing all the information necessary to retrieve these data files
        later when the query is done. To do so, call the
        `retrieve_dataset_files` with the path to this pickle file (it will be
        returned).

    outdir : str or None
        If this is provided, sets the output directory of the downloaded dataset
        files. If None, they will be downloaded to the current directory.

    maxtimeout : float
        The maximum time in seconds to wait for the LCC-Server to respond with a
        result before timing out. You can use the `retrieve_dataset_files`
        function to get results later as needed.

    refresh : float
        The time to wait in seconds before pinging the LCC-Server to see if a
        search query has completed and dataset result files can be downloaded.

    Returns
    -------

    tuple
        Returns a tuple with the following elements::

            (search result status dict,
             search result CSV file path,
             search result LC ZIP path)


<EOL>params = {<EOL>'<STR_LIT>':filters<EOL>}<EOL>if collections:<EOL><INDENT>params['<STR_LIT>'] = collections<EOL><DEDENT>if columns:<EOL><INDENT>params['<STR_LIT>'] = columns<EOL><DEDENT>if sortspec:<EOL><INDENT>params['<STR_LIT>'] = json.dumps([sortspec])<EOL><DEDENT>if samplespec:<EOL><INDENT>params['<STR_LIT>'] = int(samplespec)<EOL><DEDENT>if limitspec:<EOL><INDENT>params['<STR_LIT>'] = int(limitspec)<EOL><DEDENT>params['<STR_LIT>'] = result_visibility<EOL>params['<STR_LIT>'] = email_when_done<EOL>if email_when_done:<EOL><INDENT>download_data = False<EOL><DEDENT>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>api_url = '<STR_LIT>' % lcc_server<EOL>searchresult = submit_post_searchquery(api_url, params, apikey)<EOL>status = searchresult[<NUM_LIT:0>]<EOL>if download_data:<EOL><INDENT>if status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if pkl:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip, pkl<EOL><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT><DEDENT>elif status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout/<NUM_LIT>, refresh))<EOL>timewaited = <NUM_LIT:0.0><EOL>while timewaited < maxtimeout:<EOL><INDENT>try:<EOL><INDENT>time.sleep(refresh)<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if (csv and os.path.exists(csv) and<EOL>lczip and os.path.exists(lczip)):<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT>timewaited = timewaited + refresh<EOL><DEDENT>except KeyboardInterrupt:<EOL><INDENT>LOGWARNING('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>

This runs a column search query.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.  (e.g. for HAT, use:
        https://data.hatsurveys.org)

    filters : str or None
        This is an SQL-like string to use to filter on database columns in the
        LCC-Server's collections. To see the columns available for a search,
        visit the Collections tab in the LCC-Server's browser UI. The filter
        operators allowed are::

            lt      -> less than
            gt      -> greater than
            ge      -> greater than or equal to
            le      -> less than or equal to
            eq      -> equal to
            ne      -> not equal to
            ct      -> contains text
            isnull  -> column value is null
            notnull -> column value is not null

        You may use the `and` and `or` operators between filter specifications
        to chain them together logically.

        Example filter strings::

            "(propermotion gt 200.0) and (sdssr lt 11.0)"
            "(dered_jmag_kmag gt 2.0) and (aep_000_stetsonj gt 10.0)"
            "(gaia_status ct 'ok') and (propermotion gt 300.0)"
            "(simbad_best_objtype ct 'RR') and (dered_sdssu_sdssg lt 0.5)"

    result_visibility : {'private', 'unlisted', 'public'}
        This sets the visibility of the dataset produced from the search
        result::

               'private' -> the dataset and its products are not visible or
                            accessible by any user other than the one that
                            created the dataset.

               'unlisted' -> the dataset and its products are not visible in the
                             list of public datasets, but can be accessed if the
                             dataset URL is known

               'public' -> the dataset and its products are visible in the list
                           of public datasets and can be accessed by anyone.

    email_when_done : bool
        If True, the LCC-Server will email you when the search is complete. This
        will also set `download_data` to False. Using this requires an
        LCC-Server account and an API key tied to that account.

    collections : list of str or None
        This is a list of LC collections to search in. If this is None, all
        collections will be searched.

    columns : list of str or None
        This is a list of columns to return in the results. Matching objects'
        object IDs, RAs, DECs, and links to light curve files will always be
        returned so there is no need to specify these columns. If None, only
        these columns will be returned: 'objectid', 'ra', 'decl', 'lcfname'

    sortspec : tuple of two strs or None
        If not None, this should be a tuple of two items::

            ('column to sort by', 'asc|desc')

        This sets the column to sort the results by. For cone_search, the
        default column and sort order are 'dist_arcsec' and 'asc', meaning the
        distance from the search center in ascending order.

    samplespec : int or None
        If this is an int, will indicate how many rows from the initial search
        result will be uniformly random sampled and returned.

    limitspec : int or None
        If this is an int, will indicate how many rows from the initial search
        result to return in total.

        `sortspec`, `samplespec`, and `limitspec` are applied in this order:

            sample -> sort -> limit

    download_data : bool
        This sets if the accompanying data from the search results will be
        downloaded automatically. This includes the data table CSV, the dataset
        pickle file, and a light curve ZIP file. Note that if the search service
        indicates that your query is still in progress, this function will block
        until the light curve ZIP file becomes available. The maximum wait time
        in seconds is set by maxtimeout and the refresh interval is set by
        refresh.

        To avoid the wait block, set download_data to False and the function
        will write a pickle file to `~/.astrobase/lccs/query-[setid].pkl`
        containing all the information necessary to retrieve these data files
        later when the query is done. To do so, call the
        `retrieve_dataset_files` with the path to this pickle file (it will be
        returned).

    outdir : str or None
        If this is provided, sets the output directory of the downloaded dataset
        files. If None, they will be downloaded to the current directory.

    maxtimeout : float
        The maximum time in seconds to wait for the LCC-Server to respond with a
        result before timing out. You can use the `retrieve_dataset_files`
        function to get results later as needed.

    refresh : float
        The time to wait in seconds before pinging the LCC-Server to see if a
        search query has completed and dataset result files can be downloaded.

    Returns
    -------

    tuple
        Returns a tuple with the following elements::

            (search result status dict,
             search result CSV file path,
             search result LC ZIP path)


with open(file_to_upload) as infd:<EOL><INDENT>xmq = infd.read()<EOL><DEDENT>xmqlines = len(xmq.split('<STR_LIT:\n>')[:-<NUM_LIT:1>])<EOL>if xmqlines > <NUM_LIT>:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>file_to_upload)<EOL>return None, None, None<EOL><DEDENT>params = {'<STR_LIT>':xmq,<EOL>'<STR_LIT>':xmatch_dist_arcsec}<EOL>if collections:<EOL><INDENT>params['<STR_LIT>'] = collections<EOL><DEDENT>if columns:<EOL><INDENT>params['<STR_LIT>'] = columns<EOL><DEDENT>if filters:<EOL><INDENT>params['<STR_LIT>'] = filters<EOL><DEDENT>if sortspec:<EOL><INDENT>params['<STR_LIT>'] = json.dumps([sortspec])<EOL><DEDENT>if samplespec:<EOL><INDENT>params['<STR_LIT>'] = int(samplespec)<EOL><DEDENT>if limitspec:<EOL><INDENT>params['<STR_LIT>'] = int(limitspec)<EOL><DEDENT>params['<STR_LIT>'] = result_visibility<EOL>params['<STR_LIT>'] = email_when_done<EOL>if email_when_done:<EOL><INDENT>download_data = False<EOL><DEDENT>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>api_url = '<STR_LIT>' % lcc_server<EOL>searchresult = submit_post_searchquery(api_url, params, apikey)<EOL>status = searchresult[<NUM_LIT:0>]<EOL>if download_data:<EOL><INDENT>if status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if pkl:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip, pkl<EOL><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT><DEDENT>elif status == '<STR_LIT>':<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(maxtimeout/<NUM_LIT>, refresh))<EOL>timewaited = <NUM_LIT:0.0><EOL>while timewaited < maxtimeout:<EOL><INDENT>try:<EOL><INDENT>time.sleep(refresh)<EOL>csv, lczip, pkl = retrieve_dataset_files(searchresult,<EOL>outdir=outdir,<EOL>apikey=apikey)<EOL>if (csv and os.path.exists(csv) and<EOL>lczip and os.path.exists(lczip)):<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], csv, lczip<EOL><DEDENT>timewaited = timewaited + refresh<EOL><DEDENT>except KeyboardInterrupt:<EOL><INDENT>LOGWARNING('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return searchresult[<NUM_LIT:1>], None, None<EOL><DEDENT>

This runs a cross-match search query.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.  (e.g. for HAT, use:
        https://data.hatsurveys.org)

    file_to_upload : str
        This is the path to a text file containing objectid, RA, declination
        rows for the objects to cross-match against the LCC-Server
        collections. This should follow the format of the following example::

            # example object and coordinate list
            # objectid ra dec
            aaa 289.99698 44.99839
            bbb 293.358 -23.206
            ccc 294.197 +23.181
            ddd 19 25 27.9129 +42 47 03.693
            eee 19:25:27 -42:47:03.21
            # .
            # .
            # .
            # etc. lines starting with '#' will be ignored
            # (max 5000 objects)

    xmatch_dist_arcsec : float
        This is the maximum distance in arcseconds to consider when
        cross-matching objects in the uploaded file to the LCC-Server's
        collections. The maximum allowed distance is 30 arcseconds. Multiple
        matches to an uploaded object are possible and will be returned in order
        of increasing distance grouped by input `objectid`.

    result_visibility : {'private', 'unlisted', 'public'}
        This sets the visibility of the dataset produced from the search
        result::

               'private' -> the dataset and its products are not visible or
                            accessible by any user other than the one that
                            created the dataset.

               'unlisted' -> the dataset and its products are not visible in the
                             list of public datasets, but can be accessed if the
                             dataset URL is known

               'public' -> the dataset and its products are visible in the list
                           of public datasets and can be accessed by anyone.

    email_when_done : bool
        If True, the LCC-Server will email you when the search is complete. This
        will also set `download_data` to False. Using this requires an
        LCC-Server account and an API key tied to that account.

    collections : list of str or None
        This is a list of LC collections to search in. If this is None, all
        collections will be searched.

    columns : list of str or None
        This is a list of columns to return in the results. Matching objects'
        object IDs, RAs, DECs, and links to light curve files will always be
        returned so there is no need to specify these columns. If None, only
        these columns will be returned: 'objectid', 'ra', 'decl', 'lcfname'

    filters : str or None
        This is an SQL-like string to use to filter on database columns in the
        LCC-Server's collections. To see the columns available for a search,
        visit the Collections tab in the LCC-Server's browser UI. The filter
        operators allowed are::

            lt      -> less than
            gt      -> greater than
            ge      -> greater than or equal to
            le      -> less than or equal to
            eq      -> equal to
            ne      -> not equal to
            ct      -> contains text
            isnull  -> column value is null
            notnull -> column value is not null

        You may use the `and` and `or` operators between filter specifications
        to chain them together logically.

        Example filter strings::

            "(propermotion gt 200.0) and (sdssr lt 11.0)"
            "(dered_jmag_kmag gt 2.0) and (aep_000_stetsonj gt 10.0)"
            "(gaia_status ct 'ok') and (propermotion gt 300.0)"
            "(simbad_best_objtype ct 'RR') and (dered_sdssu_sdssg lt 0.5)"

    sortspec : tuple of two strs or None
        If not None, this should be a tuple of two items::

            ('column to sort by', 'asc|desc')

        This sets the column to sort the results by. For cone_search, the
        default column and sort order are 'dist_arcsec' and 'asc', meaning the
        distance from the search center in ascending order.

    samplespec : int or None
        If this is an int, will indicate how many rows from the initial search
        result will be uniformly random sampled and returned.

    limitspec : int or None
        If this is an int, will indicate how many rows from the initial search
        result to return in total.

        `sortspec`, `samplespec`, and `limitspec` are applied in this order:

            sample -> sort -> limit

    download_data : bool
        This sets if the accompanying data from the search results will be
        downloaded automatically. This includes the data table CSV, the dataset
        pickle file, and a light curve ZIP file. Note that if the search service
        indicates that your query is still in progress, this function will block
        until the light curve ZIP file becomes available. The maximum wait time
        in seconds is set by maxtimeout and the refresh interval is set by
        refresh.

        To avoid the wait block, set download_data to False and the function
        will write a pickle file to `~/.astrobase/lccs/query-[setid].pkl`
        containing all the information necessary to retrieve these data files
        later when the query is done. To do so, call the
        `retrieve_dataset_files` with the path to this pickle file (it will be
        returned).

    outdir : str or None
        If this is provided, sets the output directory of the downloaded dataset
        files. If None, they will be downloaded to the current directory.

    maxtimeout : float
        The maximum time in seconds to wait for the LCC-Server to respond with a
        result before timing out. You can use the `retrieve_dataset_files`
        function to get results later as needed.

    refresh : float
        The time to wait in seconds before pinging the LCC-Server to see if a
        search query has completed and dataset result files can be downloaded.

    Returns
    -------

    tuple
        Returns a tuple with the following elements::

            (search result status dict,
             search result CSV file path,
             search result LC ZIP path)


urlparams = {'<STR_LIT>':<NUM_LIT:1> if strformat else <NUM_LIT:0>,<EOL>'<STR_LIT>':page,<EOL>'<STR_LIT>':<NUM_LIT:1>}<EOL>urlqs = urlencode(urlparams)<EOL>dataset_url = '<STR_LIT>' % (lcc_server, dataset_id, urlqs)<EOL>LOGINFO('<STR_LIT>' % (lcc_server,<EOL>dataset_id,<EOL>dataset_url))<EOL>try:<EOL><INDENT>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(dataset_url, data=None, headers=headers)<EOL>resp = urlopen(req)<EOL>dataset = json.loads(resp.read())<EOL>return dataset<EOL><DEDENT>except Exception as e:<EOL><INDENT>LOGEXCEPTION('<STR_LIT>')<EOL>return None<EOL><DEDENT>

This downloads a JSON form of a dataset from the specified lcc_server.

    If the dataset contains more than 1000 rows, it will be paginated, so you
    must use the `page` kwarg to get the page you want. The dataset JSON will
    contain the keys 'npages', 'currpage', and 'rows_per_page' to help with
    this. The 'rows' key contains the actual data rows as a list of tuples.

    The JSON contains metadata about the query that produced the dataset,
    information about the data table's columns, and links to download the
    dataset's products including the light curve ZIP and the dataset CSV.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.

    dataset_id : str
        This is the unique setid of the dataset you want to get. In the results
        from the `*_search` functions above, this is the value of the
        `infodict['result']['setid']` key in the first item (the infodict) in
        the returned tuple.

    strformat : bool
        This sets if you want the returned data rows to be formatted in their
        string representations already. This can be useful if you're piping the
        returned JSON straight into some sort of UI and you don't want to deal
        with formatting floats, etc. To do this manually when strformat is set
        to False, look at the `coldesc` item in the returned dict, which gives
        the Python and Numpy string format specifiers for each column in the
        data table.

    page : int
        This sets which page of the dataset should be retrieved.

    Returns
    -------

    dict
        This returns the dataset JSON loaded into a dict.


def object_info(lcc_server, objectid, db_collection_id):

urlparams = {<EOL>'<STR_LIT>':objectid,<EOL>'<STR_LIT>':db_collection_id<EOL>}<EOL>urlqs = urlencode(urlparams)<EOL>url = '<STR_LIT>' % (lcc_server, urlqs)<EOL>try:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>' % (<EOL>objectid,<EOL>db_collection_id,<EOL>lcc_server<EOL>)<EOL>)<EOL>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(url, data=None, headers=headers)<EOL>resp = urlopen(req)<EOL>objectinfo = json.loads(resp.read())['<STR_LIT:result>']<EOL>return objectinfo<EOL><DEDENT>except HTTPError as e:<EOL><INDENT>if e.code == <NUM_LIT>:<EOL><INDENT>LOGERROR(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % (objectid,<EOL>db_collection_id)<EOL>)<EOL><DEDENT>else:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(url, e.code, e.reason))<EOL><DEDENT>return None<EOL><DEDENT>

This gets information on a single object from the LCC-Server.

    Returns a dict with all of the available information on an object, including
    finding charts, comments, object type and variability tags, and
    period-search results (if available).

    If you have an LCC-Server API key present in `~/.astrobase/lccs/` that is
    associated with an LCC-Server user account, objects that are visible to this
    user will be returned, even if they are not visible to the public. Use this
    to look up objects that have been marked as 'private' or 'shared'.

    NOTE: you can pass the result dict returned by this function directly into
    the `astrobase.checkplot.checkplot_pickle_to_png` function, e.g.::

        astrobase.checkplot.checkplot_pickle_to_png(result_dict,
                                                    'object-%s-info.png' %
                                                    result_dict['objectid'])

    to generate a quick PNG overview of the object information.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.

    objectid : str
        This is the unique database ID of the object to retrieve info for. This
        is always returned as the `db_oid` column in LCC-Server search results.

    db_collection_id : str
        This is the collection ID which will be searched for the object. This is
        always returned as the `collection` column in LCC-Server search results.

    Returns
    -------

    dict
        A dict containing the object info is returned. Some important items in
        the result dict:

        - `objectinfo`: all object magnitude, color, GAIA cross-match, and
          object type information available for this object

        - `objectcomments`: comments on the object's variability if available

        - `varinfo`: variability comments, variability features, type tags,
          period and epoch information if available

        - `neighbors`: information on the neighboring objects of this object in
          its parent light curve collection

        - `xmatch`: information on any cross-matches to external catalogs
          (e.g. KIC, EPIC, TIC, APOGEE, etc.)

        - `finderchart`: a base-64 encoded PNG image of the object's DSS2 RED
          finder chart. To convert this to an actual PNG, try the function:
          `astrobase.checkplot.pkl_io._b64_to_file`.

        - `magseries`: a base-64 encoded PNG image of the object's light
          curve. To convert this to an actual PNG, try the function:
          `astrobase.checkplot.pkl_io._b64_to_file`.

        - `pfmethods`: a list of period-finding methods applied to the object if
          any. If this list is present, use the keys in it to get to the actual
          period-finding results for each method. These will contain base-64
          encoded PNGs of the periodogram and phased light curves using the best
          three peaks in the periodogram, as well as period and epoch
          information.


urlparams = {'<STR_LIT>':nrecent}<EOL>urlqs = urlencode(urlparams)<EOL>url = '<STR_LIT>' % (lcc_server, urlqs)<EOL>try:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % (<EOL>lcc_server,<EOL>)<EOL>)<EOL>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(url, data=None, headers=headers)<EOL>resp = urlopen(req)<EOL>recent_datasets = json.loads(resp.read())['<STR_LIT:result>']<EOL>return recent_datasets<EOL><DEDENT>except HTTPError as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(url, e.code, e.reason))<EOL>return None<EOL><DEDENT>

This lists recent publicly visible datasets available on the LCC-Server.

    If you have an LCC-Server API key present in `~/.astrobase/lccs/` that is
    associated with an LCC-Server user account, datasets that belong to this
    user will be returned as well, even if they are not visible to the public.

    Parameters
    ----------

    lcc_server : str
        This is the base URL of the LCC-Server to talk to.

    nrecent : int
        This indicates how many recent public datasets you want to list. This is
        always capped at 1000.

    Returns
    -------

    list of dicts
        Returns a list of dicts, with each dict containing info on each dataset.


url = '<STR_LIT>' % lcc_server<EOL>try:<EOL><INDENT>LOGINFO(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % (<EOL>lcc_server,<EOL>)<EOL>)<EOL>have_apikey, apikey, expires = check_existing_apikey(lcc_server)<EOL>if not have_apikey:<EOL><INDENT>apikey, expires = get_new_apikey(lcc_server)<EOL><DEDENT>if apikey:<EOL><INDENT>headers = {'<STR_LIT>':'<STR_LIT>' % apikey}<EOL><DEDENT>else:<EOL><INDENT>headers = {}<EOL><DEDENT>req = Request(url, data=None, headers=headers)<EOL>resp = urlopen(req)<EOL>lcc_list = json.loads(resp.read())['<STR_LIT:result>']['<STR_LIT>']<EOL>return lcc_list<EOL><DEDENT>except HTTPError as e:<EOL><INDENT>LOGERROR('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(url, e.code, e.reason))<EOL>return None<EOL><DEDENT>

This lists all light curve collections made available on the LCC-Server.

    If you have an LCC-Server API key present in `~/.astrobase/lccs/` that is
    associated with an LCC-Server user account, light curve collections visible
    to this user will be returned as well, even if they are not visible to the
    public.

    Parameters
    ----------

    lcc_server : str
        The base URL of the LCC-Server to talk to.

    Returns
    -------

    dict
        Returns a dict containing lists of info items per collection. This
        includes collection_ids, lists of columns, lists of indexed columns,
        lists of full-text indexed columns, detailed column descriptions, number
        of objects in each collection, collection sky coverage, etc.


raproc, decproc = np.radians(ra), np.radians(dec)<EOL>if ((mu_ra != <NUM_LIT:0.0>) and (mu_dec != <NUM_LIT:0.0>) and jd):<EOL><INDENT>jd_epoch_one = JD2000 + (epoch_one - epoch_two)*<NUM_LIT><EOL>raproc = (<EOL>raproc +<EOL>(jd - jd_epoch_one)*mu_ra*MAS_P_YR_TO_RAD_P_DAY/np.cos(decproc)<EOL>)<EOL>decproc = decproc + (jd - jd_epoch_one)*mu_dec*MAS_P_YR_TO_RAD_P_DAY<EOL><DEDENT>ca = np.cos(raproc)<EOL>cd = np.cos(decproc)<EOL>sa = np.sin(raproc)<EOL>sd = np.sin(decproc)<EOL>if epoch_one != epoch_two:<EOL><INDENT>t1 = <NUM_LIT> * (epoch_two - epoch_one)<EOL>t2 = <NUM_LIT> * (epoch_one - <NUM_LIT>)<EOL>a = ( t1*ARCSEC_TO_RADIANS * (<NUM_LIT> + t2*(<NUM_LIT> + <NUM_LIT>*t2) +<EOL>t1*(<NUM_LIT> - <NUM_LIT>*t2+<NUM_LIT>*t1)) )<EOL>b = t1*t1*ARCSEC_TO_RADIANS*(<NUM_LIT> + <NUM_LIT>*t2 + <NUM_LIT>*t1) + a<EOL>c = (<EOL>ARCSEC_TO_RADIANS*t1*(<NUM_LIT> - t2*(<NUM_LIT> + <NUM_LIT>*t2) +<EOL>t1*(-<NUM_LIT> - <NUM_LIT>*t2 - <NUM_LIT>*t2))<EOL>)<EOL>sina, sinb, sinc = np.sin(a), np.sin(b), np.sin(c)<EOL>cosa, cosb, cosc = np.cos(a), np.cos(b), np.cos(c)<EOL>precmatrix = np.matrix([[cosa*cosb*cosc - sina*sinb,<EOL>sina*cosb + cosa*sinb*cosc,<EOL>cosa*sinc],<EOL>[-cosa*sinb - sina*cosb*cosc,<EOL>cosa*cosb - sina*sinb*cosc,<EOL>-sina*sinc],<EOL>[-cosb*sinc,<EOL>-sinb*sinc,<EOL>cosc]])<EOL>precmatrix = precmatrix.transpose()<EOL>x = (np.matrix([cd*ca, cd*sa, sd])).transpose()<EOL>x2 = precmatrix * x<EOL>outra = np.arctan2(x2[<NUM_LIT:1>],x2[<NUM_LIT:0>])<EOL>outdec = np.arcsin(x2[<NUM_LIT:2>])<EOL>outradeg = np.rad2deg(outra)<EOL>outdecdeg = np.rad2deg(outdec)<EOL>if outradeg < <NUM_LIT:0.0>:<EOL><INDENT>outradeg = outradeg + <NUM_LIT><EOL><DEDENT>if outscalar:<EOL><INDENT>return float(outradeg), float(outdecdeg)<EOL><DEDENT>else:<EOL><INDENT>return outradeg, outdecdeg<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return np.degrees(raproc), np.degrees(decproc)<EOL><DEDENT>

Precesses target coordinates `ra`, `dec` from `epoch_one` to `epoch_two`.

    This takes into account the jd of the observations, as well as the proper
    motion of the target mu_ra, mu_dec. Adapted from J. D. Hartman's
    VARTOOLS/converttime.c [coordprecess].

    Parameters
    ----------

    ra,dec : float
        The equatorial coordinates of the object at `epoch_one` to precess in
        decimal degrees.

    epoch_one : float
        Origin epoch to precess from to target epoch. This is a float, like:
        1985.0, 2000.0, etc.

    epoch_two : float
        Target epoch to precess from origin epoch. This is a float, like:
        2000.0, 2018.0, etc.

    jd : float
        The full Julian date to use along with the propermotions in `mu_ra`, and
        `mu_dec` to handle proper motion along with the coordinate frame
        precession. If one of `jd`, `mu_ra`, or `mu_dec` is missing, the proper
        motion will not be used to calculate the final precessed coordinates.

    mu_ra,mu_dec : float
        The proper motion in mas/yr in right ascension and declination. If these
        are provided along with `jd`, the total proper motion of the object will
        be taken into account to calculate the final precessed coordinates.

    outscalar : bool
        If True, converts the output coordinates from one-element np.arrays to
        scalars.

    Returns
    -------

    precessed_ra, precessed_dec : float
        A tuple of precessed equatorial coordinates in decimal degrees at
        `epoch_two` taking into account proper motion if `jd`, `mu_ra`, and
        `mu_dec` are provided.


<EOL>iterator = iter(iterable)<EOL>has_true = any(iterator)<EOL>has_another_true = any(iterator)<EOL>return has_true and not has_another_true<EOL>

This returns True if only one True-ish element exists in `iterable`.

    Parameters
    ----------

    iterable : iterable

    Returns
    -------

    bool
        True if only one True-ish element exists in `iterable`. False otherwise.


kwargarr = np.array([isinstance(err_t_mid,np.ndarray),<EOL>t0_fixed,<EOL>t0_percentile])<EOL>if not _single_true(kwargarr) and not np.all(~kwargarr.astype(bool)):<EOL><INDENT>raise AssertionError(<EOL>'<STR_LIT>')<EOL><DEDENT>t_mid = t_mid[np.isfinite(t_mid)]<EOL>N_midtimes = len(t_mid)<EOL>if t0_fixed:<EOL><INDENT>t0 = t0_fixed<EOL><DEDENT>elif isinstance(err_t_mid,np.ndarray):<EOL><INDENT>t0_avg = np.average(t_mid, weights=<NUM_LIT:1>/err_t_mid**<NUM_LIT:2>)<EOL>t0_options = np.arange(min(t_mid), max(t_mid)+period, period)<EOL>t0 = t0_options[np.argmin(np.abs(t0_options - t0_avg))]<EOL><DEDENT>else:<EOL><INDENT>if not t0_percentile:<EOL><INDENT>if N_midtimes % <NUM_LIT:2> == <NUM_LIT:1>:<EOL><INDENT>t0 = np.median(t_mid)<EOL><DEDENT>else:<EOL><INDENT>t0 = t_mid[int(N_midtimes/<NUM_LIT:2>)]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>t0 = np.sort(t_mid)[int(N_midtimes*t0_percentile/<NUM_LIT:100>)]<EOL><DEDENT><DEDENT>epoch = (t_mid - t0)/period<EOL>int_epoch = np.round(epoch, <NUM_LIT:0>)<EOL>if verbose:<EOL><INDENT>LOGINFO('<STR_LIT>')<EOL>LOGINFO('<STR_LIT>'.format(repr(epoch)))<EOL>LOGINFO('<STR_LIT>')<EOL>LOGINFO('<STR_LIT>'.format(repr(int_epoch)))<EOL><DEDENT>return int_epoch, t0<EOL>

This calculates the future epochs for a transit, given a period and a
    starting epoch

    The equation used is::

        t_mid = period*epoch + t0

    Default behavior if no kwargs are used is to define `t0` as the median
    finite time of the passed `t_mid` array.

    Only one of `err_t_mid` or `t0_fixed` should be passed.

    Parameters
    ----------

    t_mid : np.array
        A np.array of transit mid-time measurements

    period : float
        The period used to calculate epochs, per the equation above. For typical
        use cases, a period precise to ~1e-5 days is sufficient to get correct
        epochs.

    err_t_mid : None or np.array
        If provided, contains the errors of the transit mid-time
        measurements. The zero-point epoch is then set equal to the average of
        the transit times, weighted as `1/err_t_mid^2` . This minimizes the
        covariance between the transit epoch and the period (e.g., Gibson et
        al. 2013). For standard O-C analysis this is the best method.

    t0_fixed : None or float:
        If provided, use this t0 as the starting epoch. (Overrides all others).

    t0_percentile : None or float
        If provided, use this percentile of `t_mid` to define `t0`.

    Returns
    -------

    tuple
        This is the of the form `(integer_epoch_array, t0)`.
        `integer_epoch_array` is an array of integer epochs (float-type),
        of length equal to the number of *finite* mid-times passed.


<EOL>jdutc = astime.Time(unix_time, format='<STR_LIT>', scale='<STR_LIT>')<EOL>return jdutc.jd<EOL>

This converts UNIX time in seconds to a Julian date in UTC (JD_UTC).

    Parameters
    ----------

    unix_time : float
        A UNIX time in decimal seconds since the 1970 UNIX epoch.

    Returns
    -------

    jd : float
        The Julian date corresponding to the provided UNIX time.


jdutc = astime.Time(dt, format='<STR_LIT>',scale='<STR_LIT>')<EOL>return jdutc.jd<EOL>

This converts a Python datetime object (naive, time in UT) to JD_UTC.

    Parameters
    ----------

    dt : datetime
        A naive Python `datetime` object (e.g. with no tz attribute) measured at
        UTC.

    Returns
    -------

    jd : float
        The Julian date corresponding to the `datetime` object.


tt = astime.Time(jd, format='<STR_LIT>', scale='<STR_LIT>')<EOL>if returniso:<EOL><INDENT>return tt.iso<EOL><DEDENT>else:<EOL><INDENT>return tt.datetime<EOL><DEDENT>

This converts a UTC JD to a Python `datetime` object or ISO date string.

    Parameters
    ----------

    jd : float
        The Julian date measured at UTC.

    returniso : bool
        If False, returns a naive Python `datetime` object corresponding to
        `jd`. If True, returns the ISO format string corresponding to the date
        and time at UTC from `jd`.

    Returns
    -------

    datetime or str
        Depending on the value of `returniso`.


return astime.Time.now().jd<EOL>

Gets the Julian date at the current time.

Returns
-------

float
    The current Julian date in days.


return jd - <NUM_LIT><EOL>

Converts Julian Date to Modified Julian Date.

Parameters
----------

jd : float
    The Julian date measured at UTC.

Returns
-------

mjd : float
    `mjd = jd - 2400000.5`


return mjd + <NUM_LIT><EOL>

Converts Modified Julian date to Julian Date.

Parameters
----------

mjd : float
    The Modified Julian date measured at UTC.

Returns
-------

jd : float
    `jd = mjd + 2400000.5`


if not HAVEKERNEL:<EOL><INDENT>LOGERROR('<STR_LIT>')<EOL>return<EOL><DEDENT>rarad = np.radians(ra)<EOL>decrad = np.radians(dec)<EOL>cosra = np.cos(rarad)<EOL>sinra = np.sin(rarad)<EOL>cosdec = np.cos(decrad)<EOL>sindec = np.sin(decrad)<EOL>src_unitvector = np.array([cosdec*cosra,cosdec*sinra,sindec])<EOL>if (obslon is None) or (obslat is None) or (obsalt is None):<EOL><INDENT>t = astime.Time(jd, scale='<STR_LIT>', format='<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>t = astime.Time(jd, scale='<STR_LIT>', format='<STR_LIT>',<EOL>location=('<STR_LIT>' % obslon,<EOL>'<STR_LIT>' % obslat,<EOL>obsalt))<EOL><DEDENT>barycenter_earthmoon = jplkernel[<NUM_LIT:0>,<NUM_LIT:3>].compute(t.tdb.jd)<EOL>moonvector = (jplkernel[<NUM_LIT:3>,<NUM_LIT>].compute(t.tdb.jd) -<EOL>jplkernel[<NUM_LIT:3>,<NUM_LIT>].compute(t.tdb.jd))<EOL>pos_earth = (barycenter_earthmoon - moonvector * <NUM_LIT:1.0>/(<NUM_LIT:1.0>+EMRAT))<EOL>if jd_type == '<STR_LIT>':<EOL><INDENT>correction_seconds = np.dot(pos_earth.T, src_unitvector)/CLIGHT_KPS<EOL>correction_days = correction_seconds/SEC_P_DAY<EOL><DEDENT>elif jd_type == '<STR_LIT>':<EOL><INDENT>pos_sun = jplkernel[<NUM_LIT:0>,<NUM_LIT:10>].compute(t.tdb.jd)<EOL>sun_earth_vec = pos_earth - pos_sun<EOL>correction_seconds = np.dot(sun_earth_vec.T, src_unitvector)/CLIGHT_KPS<EOL>correction_days = correction_seconds/SEC_P_DAY<EOL><DEDENT>new_jd = t.tdb.jd + correction_days<EOL>return new_jd<EOL>

Returns BJD_TDB or HJD_TDB for input JD_UTC.

    The equation used is::

        BJD_TDB = JD_UTC + JD_to_TDB_corr + romer_delay

    where:

    - JD_to_TDB_corr is the difference between UTC and TDB JDs
    - romer_delay is the delay caused by finite speed of light from Earth-Sun

    This is based on the code at:

    https://mail.scipy.org/pipermail/astropy/2014-April/003148.html

    Note that this does not correct for:

    1. precession of coordinates if the epoch is not 2000.0
    2. precession of coordinates if the target has a proper motion
    3. Shapiro delay
    4. Einstein delay

    Parameters
    ----------

    jd : float or array-like
        The Julian date(s) measured at UTC.

    ra,dec : float
        The equatorial coordinates of the object in decimal degrees.

    obslon,obslat,obsalt : float or None
        The longitude, latitude of the observatory in decimal degrees and
        altitude of the observatory in meters. If these are not provided, the
        corrected JD will be calculated with respect to the center of the Earth.

    jd_type : {'bjd','hjd'}
        Conversion type to perform, either to Baryocentric Julian Date ('bjd')
        or to Heliocenter Julian Date ('hjd').

    Returns
    -------

    float or np.array
        The converted BJD or HJD.


def convert_constants(jmag, hmag, kmag,<EOL>cjhk,<EOL>cjh, cjk, chk,<EOL>cj, ch, ck):

if jmag is not None:<EOL><INDENT>if hmag is not None:<EOL><INDENT>if kmag is not None:<EOL><INDENT>return cjhk[<NUM_LIT:0>] + cjhk[<NUM_LIT:1>]*jmag + cjhk[<NUM_LIT:2>]*hmag + cjhk[<NUM_LIT:3>]*kmag<EOL><DEDENT>else:<EOL><INDENT>return cjh[<NUM_LIT:0>] + cjh[<NUM_LIT:1>]*jmag + cjh[<NUM_LIT:2>]*hmag<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if kmag is not None:<EOL><INDENT>return cjk[<NUM_LIT:0>] + cjk[<NUM_LIT:1>]*jmag + cjk[<NUM_LIT:2>]*kmag<EOL><DEDENT>else:<EOL><INDENT>return cj[<NUM_LIT:0>] + cj[<NUM_LIT:1>]*jmag<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if hmag is not None:<EOL><INDENT>if kmag is not None:<EOL><INDENT>return chk[<NUM_LIT:0>] + chk[<NUM_LIT:1>]*hmag + chk[<NUM_LIT:2>]*kmag<EOL><DEDENT>else:<EOL><INDENT>return ch[<NUM_LIT:0>] + ch[<NUM_LIT:1>]*hmag<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if kmag is not None:<EOL><INDENT>return ck[<NUM_LIT:0>] + ck[<NUM_LIT:1>]*kmag<EOL><DEDENT>else:<EOL><INDENT>return np.nan<EOL><DEDENT><DEDENT><DEDENT>

This converts between JHK and BVRI/SDSS mags.

    Not meant to be used directly. See the functions below for more sensible
    interface. This function does the grunt work of converting from JHK to
    either BVRI or SDSS ugriz. while taking care of missing values for any of
    jmag, hmag, or kmag.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags to use to convert.

    cjhk,cjh,cjk,chk,cj,ch,ck : lists
        Constants to use when converting.

    Returns
    -------

    float
        The converted magnitude in SDSS or BVRI system.


return convert_constants(jmag,hmag,kmag,<EOL>BJHK,<EOL>BJH, BJK, BHK,<EOL>BJ, BH, BK)<EOL>

Converts given J, H, Ks mags to a B magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted B band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>VJHK,<EOL>VJH, VJK, VHK,<EOL>VJ, VH, VK)<EOL>

Converts given J, H, Ks mags to a V magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted V band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>RJHK,<EOL>RJH, RJK, RHK,<EOL>RJ, RH, RK)<EOL>

Converts given J, H, Ks mags to an R magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted R band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>IJHK,<EOL>IJH, IJK, IHK,<EOL>IJ, IH, IK)<EOL>

Converts given J, H, Ks mags to an I magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted I band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>SDSSU_JHK,<EOL>SDSSU_JH, SDSSU_JK, SDSSU_HK,<EOL>SDSSU_J, SDSSU_H, SDSSU_K)<EOL>

Converts given J, H, Ks mags to an SDSS u magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted SDSS u band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>SDSSG_JHK,<EOL>SDSSG_JH, SDSSG_JK, SDSSG_HK,<EOL>SDSSG_J, SDSSG_H, SDSSG_K)<EOL>

Converts given J, H, Ks mags to an SDSS g magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted SDSS g band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>SDSSR_JHK,<EOL>SDSSR_JH, SDSSR_JK, SDSSR_HK,<EOL>SDSSR_J, SDSSR_H, SDSSR_K)<EOL>

Converts given J, H, Ks mags to an SDSS r magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted SDSS r band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>SDSSI_JHK,<EOL>SDSSI_JH, SDSSI_JK, SDSSI_HK,<EOL>SDSSI_J, SDSSI_H, SDSSI_K)<EOL>

Converts given J, H, Ks mags to an SDSS i magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted SDSS i band magnitude.


return convert_constants(jmag,hmag,kmag,<EOL>SDSSZ_JHK,<EOL>SDSSZ_JH, SDSSZ_JK, SDSSZ_HK,<EOL>SDSSZ_J, SDSSZ_H, SDSSZ_K)<EOL>

Converts given J, H, Ks mags to an SDSS z magnitude value.

    Parameters
    ----------

    jmag,hmag,kmag : float
        2MASS J, H, Ks mags of the object.

    Returns
    -------

    float
        The converted SDSS z band magnitude.


<EOL>d_pc = np.abs(<NUM_LIT>/gaia_parallax_mas)<EOL>if gaia_parallax_err_mas is not None:<EOL><INDENT>d_pc_err = (<EOL>(<NUM_LIT>/(gaia_parallax_mas*gaia_parallax_mas)) *<EOL>gaia_parallax_err_mas<EOL>)<EOL><DEDENT>else:<EOL><INDENT>d_pc_err = None<EOL><DEDENT>M_G = <NUM_LIT:5> - <NUM_LIT>*np.log10(d_pc) + gaia_mag<EOL>if d_pc_err is not None and gaia_mag_err is not None:<EOL><INDENT>M_G_err = np.sqrt(<EOL>((<NUM_LIT>/(d_pc * np.log(<NUM_LIT>)))**<NUM_LIT:2> * (d_pc_err)**<NUM_LIT:2>) +<EOL>gaia_mag_err*gaia_mag_err<EOL>)<EOL><DEDENT>else:<EOL><INDENT>M_G_err = None<EOL><DEDENT>if M_G_err is not None:<EOL><INDENT>return M_G, M_G_err<EOL><DEDENT>else:<EOL><INDENT>return M_G<EOL><DEDENT>

Calculates the GAIA absolute magnitude for object (or array of objects).

    Given a G mag and the parallax measured by GAIA, gets the absolute mag using
    the usual equation::

        G - M_G = 5 x log10(d_pc) - 5
        M_G = 5 - 5log10(d_pc) + G

    Parameters
    ----------

    gaia_mag : float or array-like
        The measured GAIA G magnitude.

    gaia_parallax_max : float or array-like
        The measured parallax of the object in mas.

    gaia_mag_err : float or array-like or None
        The measurement error in GAIA G magnitude.

    gaia_parallax_err_mas : float or array-like or None
        The measurement error in GAIA parallax in mas.

    Returns
    -------

    float or array-like
        The absolute magnitude M_G of the object(s).

    If both `_err` input kwargs are provided, will return a tuple of the form::

        (M_G float or array-like, M_G_err float or array-like)


tess_mag = lcdict['<STR_LIT>']['<STR_LIT>']<EOL>for key in columns:<EOL><INDENT>k1, k2 = key.split('<STR_LIT:.>')<EOL>if '<STR_LIT>' not in k2:<EOL><INDENT>lcdict[k1][k2.replace('<STR_LIT>','<STR_LIT>')] = (<EOL>tess_mag - <NUM_LIT>*np.log10(lcdict[k1][k2])<EOL>)<EOL><DEDENT>else:<EOL><INDENT>lcdict[k1][k2.replace('<STR_LIT>','<STR_LIT>')] = (<EOL>- <NUM_LIT>*np.log10(<NUM_LIT:1.0> - lcdict[k1][k2])<EOL>)<EOL><DEDENT><DEDENT>return lcdict<EOL>

This converts the normalized fluxes in the TESS lcdicts to TESS mags.

    Uses the object's TESS mag stored in lcdict['objectinfo']['tessmag']::

        mag - object_tess_mag = -2.5 log (flux/median_flux)

    Parameters
    ----------

    lcdict : lcdict
        An `lcdict` produced by `read_tess_fitslc` or
        `consolidate_tess_fitslc`. This must have normalized fluxes in its
        measurement columns (use the `normalize` kwarg for these functions).

    columns : sequence of str
        The column keys of the normalized flux and background measurements in
        the `lcdict` to operate on and convert to magnitudes in TESS band (T).

    Returns
    -------

    lcdict
        The returned `lcdict` will contain extra columns corresponding to
        magnitudes for each input normalized flux/background column.


warnings.warn(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>",<EOL>FutureWarning<EOL>)<EOL>if lctype not in ('<STR_LIT>','<STR_LIT>'):<EOL><INDENT>raise ValueError('<STR_LIT>' % lctype)<EOL><DEDENT>hdulist = pyfits.open(infile)<EOL>main_hdr = hdulist[<NUM_LIT:0>].header<EOL>lc_hdr = hdulist[<NUM_LIT:1>].header<EOL>lc = hdulist[<NUM_LIT:1>].data<EOL>if (('<STR_LIT>' not in main_hdr['<STR_LIT>']) or<EOL>('<STR_LIT>' not in lc_hdr['<STR_LIT>'])):<EOL><INDENT>raise ValueError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>time = lc['<STR_LIT>']<EOL>flux = lc['<STR_LIT>'.format(lctype)]<EOL>err_flux = lc['<STR_LIT>'.format(lctype)]<EOL>sel = (lc['<STR_LIT>'] == <NUM_LIT:0>)<EOL>sel &= np.isfinite(time)<EOL>sel &= np.isfinite(flux)<EOL>sel &= np.isfinite(err_flux)<EOL>sel &= ~np.isnan(time)<EOL>sel &= ~np.isnan(flux)<EOL>sel &= ~np.isnan(err_flux)<EOL>sel &= (time != <NUM_LIT:0>)<EOL>sel &= (flux != <NUM_LIT:0>)<EOL>sel &= (err_flux != <NUM_LIT:0>)<EOL>time = time[sel]<EOL>flux = flux[sel]<EOL>err_flux = err_flux[sel]<EOL>lc_cadence_diff = np.abs(np.nanmedian(np.diff(time))*<NUM_LIT>*<NUM_LIT> - cadence_min)<EOL>if lc_cadence_diff > <NUM_LIT>:<EOL><INDENT>raise ValueError(<EOL>'<STR_LIT>' %<EOL>cadence_min<EOL>)<EOL><DEDENT>fluxmedian = np.nanmedian(flux)<EOL>flux /= fluxmedian<EOL>err_flux /= fluxmedian<EOL>return time, flux, err_flux<EOL>

Reads TESS Ames-format FITS light curve files.

    MIT TOI alerts include Ames lightcurve files. This function gets the finite,
    nonzero times, fluxes, and errors with QUALITY == 0.

    NOTE: the PDCSAP lightcurve typically still need "pre-whitening" after this
    step.

    .. deprecated:: 0.3.20
        This function will be removed in astrobase v0.4.2. Use the
        `read_tess_fitslc` and `consolidate_tess_fitslc` functions instead.

    Parameters
    ----------

    infile : str
        The path to `*.fits.gz` TOI alert file, from Ames pipeline.

    lctype : {'PDCSAP','SAP'}
        The type of light curve to extract from the FITS LC file.

    cadence_min : int
        The expected frame cadence in units of minutes. Raises ValueError if you
        use the wrong cadence.

    Returns
    -------

    tuple
        The tuple returned is of the form:

        (times, normalized (to median) fluxes, flux errors)


<EOL>hdulist = pyfits.open(lcfits)<EOL>lchdr, lcdata = hdulist[<NUM_LIT:1>].header, hdulist[<NUM_LIT:1>].data<EOL>lctophdr, lcaperturehdr, lcaperturedata = (hdulist[<NUM_LIT:0>].header,<EOL>hdulist[<NUM_LIT:2>].header,<EOL>hdulist[<NUM_LIT:2>].data)<EOL>hdulist.close()<EOL>hdrinfo = {}<EOL>for key in headerkeys:<EOL><INDENT>if key in lchdr and lchdr[key] is not None:<EOL><INDENT>hdrinfo[key.lower()] = lchdr[key]<EOL><DEDENT>else:<EOL><INDENT>hdrinfo[key.lower()] = None<EOL><DEDENT><DEDENT>ndet = lchdr['<STR_LIT>']<EOL>for key in topkeys:<EOL><INDENT>if key in lctophdr and lctophdr[key] is not None:<EOL><INDENT>hdrinfo[key.lower()] = lctophdr[key]<EOL><DEDENT>else:<EOL><INDENT>hdrinfo[key.lower()] = None<EOL><DEDENT><DEDENT>for key in lcaperturehdr:<EOL><INDENT>if key in lcaperturehdr and lcaperturehdr[key] is not None:<EOL><INDENT>hdrinfo[key.lower()] = lcaperturehdr[key]<EOL><DEDENT>else:<EOL><INDENT>hdrinfo[key.lower()] = None<EOL><DEDENT><DEDENT>if appendto and isinstance(appendto, dict):<EOL><INDENT>lcdict = appendto<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(<EOL>hdrinfo['<STR_LIT>'] + hdrinfo['<STR_LIT>']<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(lcaperturedata)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(<EOL>(np.abs(hdrinfo['<STR_LIT>']) +<EOL>np.abs(hdrinfo['<STR_LIT>']))*<NUM_LIT>/<NUM_LIT><EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(ndet)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(hdrinfo['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(<EOL>hdrinfo['<STR_LIT>']<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'].append(<EOL>hdrinfo['<STR_LIT>']<EOL>)<EOL>for key in datakeys:<EOL><INDENT>if key.lower() in lcdict:<EOL><INDENT>lcdict[key.lower()] = (<EOL>np.concatenate((lcdict[key.lower()], lcdata[key]))<EOL>)<EOL><DEDENT><DEDENT>for key in sapkeys:<EOL><INDENT>if key.lower() in lcdict['<STR_LIT>']:<EOL><INDENT>sapflux_median = np.nanmedian(lcdata['<STR_LIT>'])<EOL>if normalize and key == '<STR_LIT>':<EOL><INDENT>thislcdata = lcdata[key] / sapflux_median<EOL><DEDENT>elif normalize and key == '<STR_LIT>':<EOL><INDENT>thislcdata = lcdata[key] / sapflux_median<EOL><DEDENT>elif normalize and key == '<STR_LIT>':<EOL><INDENT>thislcdata = lcdata[key] / sapflux_median<EOL><DEDENT>elif normalize and key == '<STR_LIT>':<EOL><INDENT>thislcdata = lcdata[key] / sapflux_median<EOL><DEDENT>else:<EOL><INDENT>thislcdata = lcdata[key]<EOL><DEDENT>lcdict['<STR_LIT>'][key.lower()] = (<EOL>np.concatenate((lcdict['<STR_LIT>'][key.lower()], thislcdata))<EOL>)<EOL><DEDENT><DEDENT>for key in pdckeys:<EOL><INDENT>if key.lower() in lcdict['<STR_LIT>']:<EOL><INDENT>pdcsap_flux_median = np.nanmedian(lcdata['<STR_LIT>'])<EOL>if normalize and key == '<STR_LIT>':<EOL><INDENT>thislcdata = lcdata[key] / pdcsap_flux_median<EOL><DEDENT>elif normalize and key == '<STR_LIT>':<EOL><INDENT>thislcdata = lcdata[key] / pdcsap_flux_median<EOL><DEDENT>else:<EOL><INDENT>thislcdata = lcdata[key]<EOL><DEDENT>lcdict['<STR_LIT>'][key.lower()] = (<EOL>np.concatenate((lcdict['<STR_LIT>'][key.lower()], thislcdata))<EOL>)<EOL><DEDENT><DEDENT>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype=np.float64))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype=np.int64))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype=np.int64))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype=np.int64))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype=np.int64))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype='<STR_LIT>'))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype='<STR_LIT>'))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype='<STR_LIT>'))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype='<STR_LIT>'))<EOL>)<EOL>lcdict['<STR_LIT>'] = np.concatenate(<EOL>(lcdict['<STR_LIT>'],<EOL>np.full_like(lcdata['<STR_LIT>'],<EOL>hdrinfo['<STR_LIT>'],<EOL>dtype=np.int64))<EOL>)<EOL><DEDENT>else:<EOL><INDENT>lcdict = {<EOL>'<STR_LIT>':hdrinfo['<STR_LIT:object>'],<EOL>'<STR_LIT>':{<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>'] + hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[lcaperturedata],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[(np.abs(hdrinfo['<STR_LIT>']) +<EOL>np.abs(hdrinfo['<STR_LIT>']))*<NUM_LIT>/<NUM_LIT>],<EOL>'<STR_LIT>':[ndet],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>},<EOL>'<STR_LIT>':{<EOL>'<STR_LIT>':hdrinfo['<STR_LIT:object>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':hdrinfo['<STR_LIT>'],<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>'<STR_LIT>':'<STR_LIT>',<EOL>},<EOL>'<STR_LIT>':{<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>'<STR_LIT>':[hdrinfo['<STR_LIT>']],<EOL>},<EOL>'<STR_LIT>':{},<EOL>'<STR_LIT>':{},<EOL>}<EOL>for key in datakeys:<EOL><INDENT>lcdict[key.lower()] = lcdata[key]<EOL><DEDENT>for key in sapkeys:<EOL><INDENT>lcdict['<STR_LIT>'][key.lower()] = lcdata[key]<EOL><DEDENT>for key in pdckeys:<EOL><INDENT>lcdict['<STR_LIT>'][key.lower()] = lcdata[key]<EOL><DEDENT>lcdict['<STR_LIT>'] = np.full_like(lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype=np.float64)<EOL>lcdict['<STR_LIT>'] = np.full_like(lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype=np.int64)<EOL>lcdict['<STR_LIT>'] = np.full_like(lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype=np.int64)<EOL>lcdict['<STR_LIT>'] = np.full_like(lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype=np.int64)<EOL>lcdict['<STR_LIT>'] = np.full_like(<EOL>lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype=np.int64,<EOL>)<EOL>lcdict['<STR_LIT>'] = np.full_like(<EOL>lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype='<STR_LIT>',<EOL>)<EOL>lcdict['<STR_LIT>'] = np.full_like(<EOL>lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype='<STR_LIT>',<EOL>)<EOL>lcdict['<STR_LIT>'] = np.full_like(<EOL>lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype='<STR_LIT>',<EOL>)<EOL>lcdict['<STR_LIT>'] = np.full_like(<EOL>lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype='<STR_LIT>',<EOL>)<EOL>lcdict['<STR_LIT>'] = np.full_like(<EOL>lcdict['<STR_LIT:time>'],<EOL>lcdict['<STR_LIT>']['<STR_LIT>'][<NUM_LIT:0>],<EOL>dtype=np.int64,<EOL>)<EOL>if normalize:<EOL><INDENT>sapflux_median = np.nanmedian(lcdict['<STR_LIT>']['<STR_LIT>'])<EOL>pdcsap_flux_median = np.nanmedian(lcdict['<STR_LIT>']['<STR_LIT>'])<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = (<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] /<EOL>sapflux_median<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = (<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] /<EOL>sapflux_median<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = (<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] /<EOL>sapflux_median<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = (<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] /<EOL>sapflux_median<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = (<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] /<EOL>pdcsap_flux_median<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = (<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] /<EOL>pdcsap_flux_median<EOL>)<EOL><DEDENT><DEDENT>lcdict['<STR_LIT>'] = (<EOL>[x.lower() for x in datakeys] +<EOL>['<STR_LIT>' % x.lower() for x in sapkeys] +<EOL>['<STR_LIT>' % x.lower() for x in pdckeys] +<EOL>['<STR_LIT>','<STR_LIT>','<STR_LIT>','<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>']<EOL>)<EOL>lcdict['<STR_LIT>']['<STR_LIT>'] = sum(lcdict['<STR_LIT>']['<STR_LIT>'])<EOL>if (filterqualityflags is not False or<EOL>nanfilter is not None or<EOL>timestoignore is not None):<EOL><INDENT>lcdict = filter_tess_lcdict(lcdict,<EOL>filterqualityflags,<EOL>nanfilter=nanfilter,<EOL>timestoignore=timestoignore)<EOL><DEDENT>return lcdict<EOL>

This extracts the light curve from a single TESS .lc.fits file.

    This works on the light curves available at MAST.

    TODO: look at:

    https://archive.stsci.edu/missions/tess/doc/EXP-TESS-ARC-ICD-TM-0014.pdf

    for details on the column descriptions and to fill in any other info we
    need.

    Parameters
    ----------

    lcfits : str
        The filename of a MAST Kepler/K2 light curve FITS file.

    headerkeys : list
        A list of FITS header keys that will be extracted from the FITS light
        curve file. These describe the observations. The default value for this
        is given in `LCHEADERKEYS` above.

    datakeys : list
        A list of FITS column names that correspond to the auxiliary
        measurements in the light curve. The default is `LCDATAKEYS` above.

    sapkeys : list
        A list of FITS column names that correspond to the SAP flux
        measurements in the light curve. The default is `LCSAPKEYS` above.

    pdckeys : list
        A list of FITS column names that correspond to the PDC flux
        measurements in the light curve. The default is `LCPDCKEYS` above.

    topkeys : list
        A list of FITS header keys that describe the object in the light
        curve. The default is `LCTOPKEYS` above.

    apkeys : list
        A list of FITS header keys that describe the flux measurement apertures
        used by the TESS pipeline. The default is `LCAPERTUREKEYS` above.

    normalize : bool
        If True, then the light curve's SAP_FLUX and PDCSAP_FLUX measurements
        will be normalized to 1.0 by dividing out the median flux for the
        component light curve.

    appendto : lcdict or None
        If appendto is an `lcdict`, will append measurements of this `lcdict` to
        that `lcdict`. This is used for consolidating light curves for the same
        object across different files (sectors/cameras/CCDs?). The appending
        does not care about the time order. To consolidate light curves in time
        order, use `consolidate_tess_fitslc` below.

    filterqualityflags : bool
        If True, will remove any measurements that have non-zero quality flags
        present. This usually indicates an issue with the instrument or
        spacecraft.

    nanfilter : {'sap','pdc','sap,pdc'} or None
        Indicates the flux measurement type(s) to apply the filtering to.

    timestoignore : list of tuples or None
        This is of the form::

            [(time1_start, time1_end), (time2_start, time2_end), ...]

        and indicates the start and end times to mask out of the final
        lcdict. Use this to remove anything that wasn't caught by the quality
        flags.

    Returns
    -------

    lcdict
        Returns an `lcdict` (this is useable by most astrobase functions for LC
        processing).


<EOL>if isinstance(lclist, str):<EOL><INDENT>if sys.version_info[:<NUM_LIT:2>] > (<NUM_LIT:3>,<NUM_LIT:4>):<EOL><INDENT>matching = glob.glob(lclist,<EOL>recursive=True)<EOL>LOGINFO('<STR_LIT>' % (len(matching), matching))<EOL><DEDENT>else:<EOL><INDENT>lcfitsdir = os.path.dirname(lclist)<EOL>lcfitsfile = os.path.basename(lclist)<EOL>walker = os.walk(lcfitsdir)<EOL>matching = []<EOL>for root, dirs, _files in walker:<EOL><INDENT>for sdir in dirs:<EOL><INDENT>searchpath = os.path.join(root,<EOL>sdir,<EOL>lcfitsfile)<EOL>foundfiles = glob.glob(searchpath)<EOL>if foundfiles:<EOL><INDENT>matching.extend(foundfiles)<EOL>LOGINFO(<EOL>'<STR_LIT>' % (repr(foundfiles),<EOL>os.path.join(root,sdir))<EOL>)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>if len(matching) == <NUM_LIT:0>:<EOL><INDENT>LOGERROR('<STR_LIT>' %<EOL>lclist)<EOL>return None<EOL><DEDENT><DEDENT>else:<EOL><INDENT>matching = lclist<EOL><DEDENT>consolidated = read_tess_fitslc(matching[<NUM_LIT:0>],<EOL>normalize=normalize,<EOL>headerkeys=LCHEADERKEYS,<EOL>datakeys=LCDATAKEYS,<EOL>sapkeys=LCSAPKEYS,<EOL>pdckeys=LCPDCKEYS,<EOL>topkeys=LCTOPKEYS,<EOL>apkeys=LCAPERTUREKEYS)<EOL>if len(matching) > <NUM_LIT:1>:<EOL><INDENT>for lcf in matching[<NUM_LIT:1>:]:<EOL><INDENT>consolidated = read_tess_fitslc(lcf,<EOL>appendto=consolidated,<EOL>normalize=normalize,<EOL>headerkeys=LCHEADERKEYS,<EOL>datakeys=LCDATAKEYS,<EOL>sapkeys=LCSAPKEYS,<EOL>pdckeys=LCPDCKEYS,<EOL>topkeys=LCTOPKEYS,<EOL>apkeys=LCAPERTUREKEYS)<EOL><DEDENT><DEDENT>LOGINFO('<STR_LIT>')<EOL>finiteind = np.isfinite(consolidated['<STR_LIT:time>'])<EOL>if np.sum(finiteind) < consolidated['<STR_LIT:time>'].size:<EOL><INDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>column_sort_ind = np.argsort(consolidated['<STR_LIT:time>'])<EOL>for col in consolidated['<STR_LIT>']:<EOL><INDENT>if '<STR_LIT:.>' in col:<EOL><INDENT>key, subkey = col.split('<STR_LIT:.>')<EOL>consolidated[key][subkey] = (<EOL>consolidated[key][subkey][column_sort_ind]<EOL>)<EOL><DEDENT>else:<EOL><INDENT>consolidated[col] = consolidated[col][column_sort_ind]<EOL><DEDENT><DEDENT>info_sort_ind = np.argsort(consolidated['<STR_LIT>']['<STR_LIT>'])<EOL>for key in consolidated['<STR_LIT>']:<EOL><INDENT>consolidated['<STR_LIT>'][key] = (<EOL>np.array(consolidated['<STR_LIT>'][key])[info_sort_ind].tolist()<EOL>)<EOL><DEDENT>for key in consolidated['<STR_LIT>']:<EOL><INDENT>consolidated['<STR_LIT>'][key] = (<EOL>np.array(consolidated['<STR_LIT>'][key])[info_sort_ind].tolist()<EOL>)<EOL><DEDENT>if (filterqualityflags is not False or<EOL>nanfilter is not None or<EOL>timestoignore is not None):<EOL><INDENT>consolidated = filter_tess_lcdict(consolidated,<EOL>filterqualityflags,<EOL>nanfilter=nanfilter,<EOL>timestoignore=timestoignore)<EOL><DEDENT>return consolidated<EOL>

This consolidates a list of LCs for a single TIC object.

    NOTE: if light curve time arrays contain nans, these and their associated
    measurements will be sorted to the end of the final combined arrays.

    Parameters
    ----------

    lclist : list of str, or str
        `lclist` is either a list of actual light curve files or a string that
        is valid for glob.glob to search for and generate a light curve list
        based on the file glob. This is useful for consolidating LC FITS files
        across different TESS sectors for a single TIC ID using a glob like
        `*<TICID>*_lc.fits`.

    normalize : bool
        If True, then the light curve's SAP_FLUX and PDCSAP_FLUX measurements
        will be normalized to 1.0 by dividing out the median flux for the
        component light curve.

    filterqualityflags : bool
        If True, will remove any measurements that have non-zero quality flags
        present. This usually indicates an issue with the instrument or
        spacecraft.

    nanfilter : {'sap','pdc','sap,pdc'} or None
        Indicates the flux measurement type(s) to apply the filtering to.

    timestoignore : list of tuples or None
        This is of the form::

            [(time1_start, time1_end), (time2_start, time2_end), ...]

        and indicates the start and end times to mask out of the final
        lcdict. Use this to remove anything that wasn't caught by the quality
        flags.

    headerkeys : list
        A list of FITS header keys that will be extracted from the FITS light
        curve file. These describe the observations. The default value for this
        is given in `LCHEADERKEYS` above.

    datakeys : list
        A list of FITS column names that correspond to the auxiliary
        measurements in the light curve. The default is `LCDATAKEYS` above.

    sapkeys : list
        A list of FITS column names that correspond to the SAP flux
        measurements in the light curve. The default is `LCSAPKEYS` above.

    pdckeys : list
        A list of FITS column names that correspond to the PDC flux
        measurements in the light curve. The default is `LCPDCKEYS` above.

    topkeys : list
        A list of FITS header keys that describe the object in the light
        curve. The default is `LCTOPKEYS` above.

    apkeys : list
        A list of FITS header keys that describe the flux measurement apertures
        used by the TESS pipeline. The default is `LCAPERTUREKEYS` above.

    Returns
    -------

    lcdict
        Returns an `lcdict` (this is useable by most astrobase functions for LC
        processing).


if not outfile:<EOL><INDENT>outfile = '<STR_LIT>' % lcdict['<STR_LIT>'].replace('<STR_LIT:U+0020>','<STR_LIT>')<EOL><DEDENT>with open(outfile,'<STR_LIT:wb>') as outfd:<EOL><INDENT>pickle.dump(lcdict, outfd, protocol=pickle.HIGHEST_PROTOCOL)<EOL><DEDENT>return os.path.abspath(outfile)<EOL>

This writes the `lcdict` to a Python pickle.

    Parameters
    ----------

    lcdict : lcdict
        This is the input `lcdict` to write to a pickle.

    outfile : str or None
        If this is None, the object's Kepler ID/EPIC ID will determined from the
        `lcdict` and used to form the filename of the output pickle file. If
        this is a `str`, the provided filename will be used.

    Returns
    -------

    str
        The absolute path to the written pickle file.


if picklefile.endswith('<STR_LIT>'):<EOL><INDENT>infd = gzip.open(picklefile, '<STR_LIT:rb>')<EOL><DEDENT>else:<EOL><INDENT>infd = open(picklefile, '<STR_LIT:rb>')<EOL><DEDENT>try:<EOL><INDENT>with infd:<EOL><INDENT>lcdict = pickle.load(infd)<EOL><DEDENT><DEDENT>except UnicodeDecodeError:<EOL><INDENT>with open(picklefile,'<STR_LIT:rb>') as infd:<EOL><INDENT>lcdict = pickle.load(infd, encoding='<STR_LIT>')<EOL><DEDENT>LOGWARNING('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>' % picklefile)<EOL><DEDENT>return lcdict<EOL>

This turns the pickled lightcurve file back into an `lcdict`.

    Parameters
    ----------

    picklefile : str
        The path to a previously written Kepler LC picklefile generated by
        `tess_lcdict_to_pkl` above.

    Returns
    -------

    lcdict
        Returns an `lcdict` (this is useable by most astrobase functions for LC
        processing).


cols = lcdict['<STR_LIT>']<EOL>if filterqualityflags:<EOL><INDENT>nbefore = lcdict['<STR_LIT:time>'].size<EOL>filterind = lcdict['<STR_LIT>'] == <NUM_LIT:0><EOL>for col in cols:<EOL><INDENT>if '<STR_LIT:.>' in col:<EOL><INDENT>key, subkey = col.split('<STR_LIT:.>')<EOL>lcdict[key][subkey] = lcdict[key][subkey][filterind]<EOL><DEDENT>else:<EOL><INDENT>lcdict[col] = lcdict[col][filterind]<EOL><DEDENT><DEDENT>nafter = lcdict['<STR_LIT:time>'].size<EOL>if not quiet:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>% (nbefore, nafter))<EOL><DEDENT><DEDENT>if nanfilter and nanfilter == '<STR_LIT>':<EOL><INDENT>notnanind = (<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT:time>'])<EOL>)<EOL><DEDENT>elif nanfilter and nanfilter == '<STR_LIT>':<EOL><INDENT>notnanind = (<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT:time>'])<EOL>)<EOL><DEDENT>elif nanfilter and nanfilter == '<STR_LIT>':<EOL><INDENT>notnanind = (<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT>']['<STR_LIT>']) &<EOL>np.isfinite(lcdict['<STR_LIT:time>'])<EOL>)<EOL><DEDENT>elif nanfilter is None:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>raise NotImplementedError<EOL><DEDENT>if nanfilter:<EOL><INDENT>nbefore = lcdict['<STR_LIT:time>'].size<EOL>for col in cols:<EOL><INDENT>if '<STR_LIT:.>' in col:<EOL><INDENT>key, subkey = col.split('<STR_LIT:.>')<EOL>lcdict[key][subkey] = lcdict[key][subkey][notnanind]<EOL><DEDENT>else:<EOL><INDENT>lcdict[col] = lcdict[col][notnanind]<EOL><DEDENT><DEDENT>nafter = lcdict['<STR_LIT:time>'].size<EOL>if not quiet:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>% (nbefore, nafter))<EOL><DEDENT><DEDENT>if (timestoignore and<EOL>isinstance(timestoignore, list) and<EOL>len(timestoignore) > <NUM_LIT:0>):<EOL><INDENT>exclind = np.full_like(lcdict['<STR_LIT:time>'],True).astype(bool)<EOL>nbefore = exclind.size<EOL>for ignoretime in timestoignore:<EOL><INDENT>time0, time1 = ignoretime[<NUM_LIT:0>], ignoretime[<NUM_LIT:1>]<EOL>thismask = ~((lcdict['<STR_LIT:time>'] >= time0) & (lcdict['<STR_LIT:time>'] <= time1))<EOL>exclind = exclind & thismask<EOL><DEDENT>for col in cols:<EOL><INDENT>if '<STR_LIT:.>' in col:<EOL><INDENT>key, subkey = col.split('<STR_LIT:.>')<EOL>lcdict[key][subkey] = lcdict[key][subkey][exclind]<EOL><DEDENT>else:<EOL><INDENT>lcdict[col] = lcdict[col][exclind]<EOL><DEDENT><DEDENT>nafter = lcdict['<STR_LIT:time>'].size<EOL>if not quiet:<EOL><INDENT>LOGINFO('<STR_LIT>'<EOL>% (nbefore, nafter))<EOL><DEDENT><DEDENT>return lcdict<EOL>

This filters the provided TESS `lcdict`, removing nans and bad
    observations.

    By default, this function removes points in the TESS LC that have ANY
    quality flags set.

    Parameters
    ----------

    lcdict : lcdict
        An `lcdict` produced by `consolidate_tess_fitslc` or
        `read_tess_fitslc`.

    filterflags : bool
        If True, will remove any measurements that have non-zero quality flags
        present. This usually indicates an issue with the instrument or
        spacecraft.

    nanfilter : {'sap','pdc','sap,pdc'}
        Indicates the flux measurement type(s) to apply the filtering to.

    timestoignore : list of tuples or None
        This is of the form::

            [(time1_start, time1_end), (time2_start, time2_end), ...]

        and indicates the start and end times to mask out of the final
        lcdict. Use this to remove anything that wasn't caught by the quality
        flags.

    Returns
    -------

    lcdict
        Returns an `lcdict` (this is useable by most astrobase functions for LC
        processing). The `lcdict` is filtered IN PLACE!