Load files as a table of data products#

  1#!/usr/bin/env python
  2# Load files as a table of data products
  3
  4from argparse import ArgumentParser, HelpFormatter
  5import csv
  6from glob import glob
  7import os
  8import tempfile
  9import textwrap
 10
 11import firefly_client
 12
 13
 14# From https://stackoverflow.com/a/64102901
 15class RawFormatter(HelpFormatter):
 16    def _fill_text(self, text, width, indent):
 17        return "\n".join(
 18            [
 19                textwrap.fill(line, width)
 20                for line in textwrap.indent(textwrap.dedent(text), indent).splitlines()
 21            ]
 22        )
 23
 24
 25def filetable_to_firefly(
 26    ffclient, topdir, pattern, path_prefix="", recursive=True, sort=False
 27):
 28    """Upload table of files matching a pattern to a FireflyClient
 29
 30    Parameters:
 31    -----------
 32    ffclient: firefly_client.FireflyClient
 33        Instance of FireflyClient connected to a Firefly server
 34
 35    topdir: "str"
 36        pathname for directory to search
 37
 38    pattern: "str"
 39        filename pattern to search for, e.g. "*.fits"
 40
 41    path_prefix: "str"
 42        string to prepend to each file path after "file://"
 43        for example, specify "/external" for Firefly-in-Docker
 44        (default="")
 45
 46    recursive: `bool`
 47        Search all subdirectories recursively (default=True)
 48
 49    sort: `bool`
 50        Sort the file paths (default=False)
 51
 52    Returns:
 53    --------
 54    tbl_val: "str"
 55        Descriptor of table that was uploaded to the Firefly server
 56
 57    metadict: `dict`
 58        Dictionary of metadata items
 59
 60    """
 61    if recursive:
 62        file_lookup_path = os.path.join(topdir, "**", pattern)
 63    else:
 64        file_lookup_path = os.path.join(topdir, pattern)
 65    filelist = glob(file_lookup_path, recursive=recursive)
 66    if sort:
 67        filelist = sorted(filelist)
 68    metadict = {"datasource": "path"}
 69    with tempfile.NamedTemporaryFile(mode="w+t", delete=False, suffix=".csv") as fd:
 70        csv_writer = csv.writer(fd)
 71        csv_writer.writerow(["number", "name", "path"])
 72        for i, path in enumerate(filelist):
 73            # Docker Firefly allows uploads from /external
 74            csv_writer.writerow(
 75                [i, os.path.basename(path), "file://" + path_prefix + path]
 76            )
 77
 78    tbl_val = ffclient.upload_file(fd.name)
 79    os.remove(fd.name)
 80    return (tbl_val, metadict)
 81
 82
 83# Sample application
 84def main():
 85    parser = ArgumentParser(
 86        description="""
 87        Display a table of files in a Firefly window.
 88        
 89        Note that you must be running a Firefly server that is
 90        local to the data.
 91        """,
 92        epilog="""
 93        If running Firefly via Docker, note that you can mount your
 94        disk area onto /external.
 95        
 96        Sample command for running the Firefly server:
 97            docker run -p 8090:8080  -e "MAX_JVM_SIZE=64G"  \\
 98            -e "LOG_FILE_TO_CONSOLE=firefly.log" --rm --name ncmds_firefly \\
 99            -v /neoswork:/external/neoswork ipac/firefly:latest
100        """,
101        formatter_class=RawFormatter,
102    )
103    parser.add_argument("topdir", help="top-level directory to search")
104    parser.add_argument("pattern", help="filename pattern for search")
105    parser.add_argument(
106        "--path_prefix",
107        help=textwrap.dedent(
108            """string to prepend to file paths,
109        e.g. specify '/external' for Firefly-in-Docker"""
110        ),
111        default="",
112    )
113    parser.add_argument(
114        "--norecursion", help="do not recursively search topdir", action="store_true"
115    )
116    parser.add_argument("--sort", help="sort the file paths", action="store_true")
117    parser.add_argument(
118        "--firefly_url", help="URL for Firefly server", default=os.getenv("FIREFLY_URL")
119    )
120    parser.add_argument("--channel", help="channel name for websocket", default=None)
121    parser.add_argument(
122        "--html_file",
123        help="Firefly landing page (default 'firefly.html')",
124        default="firefly.html",
125    )
126    parser.add_argument(
127        "--printurl",
128        help="print browser url instead of" + " attempting to launch browser",
129        action="store_true",
130    )
131
132    args = parser.parse_args()
133    topdir = args.topdir
134    pattern = args.pattern
135    firefly_url = args.firefly_url
136    channel = args.channel
137    printurl = args.printurl
138    launch_browser = False if printurl else True
139    recursion = not args.norecursion
140    sort = args.sort
141    path_prefix = args.path_prefix
142    html_file = args.html_file
143
144    fc = firefly_client.FireflyClient.make_client(
145        url=firefly_url,
146        channel_override=channel,
147        html_file=html_file,
148        launch_browser=launch_browser,
149    )
150    if printurl:
151        print("Firefly URL is {}".format(fc.get_firefly_url()))
152
153    print("Searching for files...", end="")
154    tbl_val, metainfo = filetable_to_firefly(
155        fc, topdir, pattern, path_prefix=path_prefix, recursive=recursion, sort=sort
156    )
157    print("done.")
158
159    if printurl:
160        input("Press Enter after you have opened the Firefly URL printed above...")
161
162    # TODO: figure out how to activate data products (meta) tab in Bi-View
163    # if "slate" not in html_file:
164    #     fc.change_triview_layout(firefly_client.FireflyClient.BIVIEW_T_IChCov)
165    #     fc.dispatch('layout.updateLayout', {'images':{'selectedTab':'meta'}})
166    r = fc.add_cell(0, 0, 1, 2, "tables", "main")
167    fc.show_table(tbl_val, meta=metainfo)
168    r = fc.add_cell(0, 1, 1, 2, "tableImageMeta", "image-meta")
169    fc.show_image_metadata(viewer_id=r["cell_id"])
170
171
172if __name__ == "__main__":
173    main()