Skip to content
Snippets Groups Projects
oceano.py 7.95 KiB
Newer Older
import argparse
import sys
import myPySimpleGUI as sg
# import PySimpleGUIQt as sg
import toml
import logging
from file_extractor import FileExtractor
import pathlib
from configparser import ConfigParser
import os
import distutils.util as du
# typeInstrument is a dictionary as key: files extension
typeInstrument = {'CTD': ('cnv', 'CNV'), 'XBT': (
    'EDF', 'edf'), 'LADCP': ('lad', 'LAD'), 'TSG': 'COLCOR'}
ti = typeInstrument  # an alias
def processArgs():
    parser = argparse.ArgumentParser(
        description='This program read multiple ASCII file, extract physical parameter \
                    following ROSCOP codification at the given column, fill arrays, write header file ',
        usage='\npython oceano.py data/CTD/cnv/dfr2900[1-3].cnv -i CTD -d\n'
        'python oceano.py data/CTD/cnv/dfr2900[1-3].cnv -i CTD -k PRES TEMP PSAL DOX2 DENS\n'
        'python oceano.py data/CTDcnv/dfr29*.cnv -d\n'
        'python oceano.py data/XBT/T7_0000*.EDF -i XBT -k DEPTH TEMP SVEL\n'
        "python oceano.py data/LADCP/*.lad -i LADCP -k DEPTH EWCT NSCT",
        epilog='J. Grelet IRD US191 - March 2019')
    parser.add_argument('-d', '--debug', help='display debug informations',
                        action='store_true')
jacques Grelet's avatar
jacques Grelet committed
    parser.add_argument('--demo', nargs='?', default='CTD',
                        help='specify the commande line for instrument, eg CTD, XBT, TSG, LADCP (default: %(default)s)')
    parser.add_argument('-c', '--config', help="toml configuration file, (default: %(default)s)",
                        default='tests/test.toml')
    parser.add_argument('-i', '--instrument', nargs='?', default='CTD',
                        help='specify the instrument that produce files, eg CTD, XBT, TSG, LADCP (default: %(default)s)')
    parser.add_argument('-k', '--key', nargs='+', default=['PRES', 'TEMP', 'PSAL'],
                        help='display dictionary for key(s), (default: %(default)s)')
    parser.add_argument('-g', '--gui', action='store_true',
                        help='use GUI interface')
    parser.add_argument('files', nargs='*',
                        help='cnv file(s) to parse, (default: data/cnv/dfr29*.cnv)')
    return parser


def defineGUI():
    # change look and feel color scheme
    sg.ChangeLookAndFeel('SandyBeach')

    # define GUI layout
    layout = ([[sg.Text('File(s) to read and convert')],
               [sg.Multiline(size=(40, 5), key='_IN_'),
                sg.Input(key='_HIDDEN_', visible=False,
                         enable_events=True),
                sg.FilesBrowse(key='_HIDDEN_',
                               tooltip='Choose one or more files',
                               initial_folder='data/{}'.format(ti[device][0]))],
               [sg.Combo(list(ti.keys()), enable_events=True, size=(8, 1),
                         key='_COMBO_', tooltip='Select the instrument')],
               * [[sg.Checkbox(k, key=k,
                               tooltip='Select the extract the physical parameter {}'.format(k))] for k in keys],
               [sg.OK(), sg.CloseButton('Cancel')]])
    # [sg.CloseButton('Run'), sg.CloseButton('Cancel')]])

    # create a local instance windows used to reload the saved config from file
    window = sg.Window('Oceano converter').Layout(layout)
    window.LoadFromDisk(configfile)
    window.Finalize
    return window


def updateFilesBrowseCombo(extentions):
    e = window.Rows[1][2]   # hardcoded
    e.FileTypes = []      # init to empty list
    for ext in extentions:
        e.FileTypes.append(("{} files".format(ext), "*.{}".format(ext)))
def process(args, cfg, ti):
    '''
    Extract data from ASCII files and return FileExtractor instannce and array size of extracted data

    Parameters
    ----------
        args : ConfigParser
        cfg : dict
            toml instance describing the file structure to decode
        ti : str {'CNV', 'XBT','LADCP','TSG',}
            The typeInstrument key

    Returns
    -------
        fe: FileExtractor
        n, m: array size
    '''
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed

    # check if no file selected or cancel button pressed
    logging.debug("File(s): {}, config: {}, Keys: {}".format(
        args.files, args.config, args.key))

    # fileExtractor
    fe = FileExtractor(args.files)

    # cfg = toml.load(args.config)
    [n, m] = fe.firstPass()
    # fe.secondPass(['PRES', 'TEMP', 'PSAL', 'DOX2'], cfg, 'ctd')
    fe.secondPass(args.key, cfg, ti)
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    # fe.disp(['PRES', 'TEMP', 'PSAL', 'DOX2'])
    return fe, n, m


if __name__ == "__main__":
    '''
    usage:
    > python oceano.py data/CTD/cnv/dfr2900[1-3].cnv -d
    > python oceano.py data/CTD/cnv/dfr2900[1-3].cnv -k PRES TEMP PSAL DOX2 DENS
    > python oceano.py data/CTD/cnv/dfr29*.cnv -d
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    '''
    # recover and process line arguments
    parser = processArgs()
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    args = parser.parse_args()

    # initialize filename use to save GUI configuration
    configfile = 'oceano.cfg'

    # set looging mode if debug
    if args.debug:
        logging.basicConfig(
            format='%(levelname)s:%(message)s', level=logging.DEBUG)

    # read config Toml file and get the physical parameter list (Roscop code) for the specified instrument
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    cfg = toml.load(args.config)
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    device = str(args.instrument)  # convert one element list to str
    keys = cfg['split'][device.lower()].keys()
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed

    # test arguements from sys.argv, args is never to None with default option set
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    if args.gui or len(sys.argv) == 1:
        # setup the GUI windows Layout
        window = defineGUI()
        updateFilesBrowseCombo(ti[device])
        # main GUI loop
        while True:
           # display the main windows
            event, values = window.Read()
            # print(event, values)
            if event is 'Cancel' or event == None:
                raise SystemExit("Cancelling: user exit")

            if event is 'OK':  # end of initialization, process data now
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
            if event is '_COMBO_':
                # you have to go into the bowels of the pygi code, to get the instance of the Combo
                # by the line and column number of the window to update its "fileType" property.
                updateFilesBrowseCombo(ti[values['_COMBO_']])
            # update the Multilines instance from FilesBrowse return
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
            if event is '_HIDDEN_':
                window.Element('_IN_').Update(
                    values['_HIDDEN_'].split(';'))
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        # save program configuration
        window.SaveToDisk(configfile)

        # debug return values from GUI
        logging.debug("Event: {}, Values: {}".format(event, values))

        # extract selected parameters (true) from dict values
        new_values = values.copy()
        for k in values.keys():
            if k[0] == '_' or values[k] == False:
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
                del new_values[k]
        args.key = new_values.keys()

jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        # values['_HIDDEN_'] is a string with files separated by ';' and fileExtractor need a list
        files = values['_HIDDEN_'].split(';')
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        args.files = files

        # test if a or more file are selected
        if not all(args.files):
            sg.Popup("Cancel", "No filename supplied")
            raise SystemExit("Cancelling: no filename supplied")

        # process of files start here
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        fe, n, m = process(args, cfg, values['_COMBO_'])
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed

        # display result in popup GUI
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        dims = "Dimensions: {} x {}".format(n, m)
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        sg.PopupScrolled('Oceano2python', dims,
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
                         fe.disp(args.key),  size=(80, 40))
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        # It will output to a debug window. Bug ? debug windows xas closed before exiting program
        # print = sg.Print
        # or
        # print = sg.Print(size=(80,40))

jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
    else:
        # test if a or more file are selected
        if args.files == []:
            print('You need to specify one or more files to process !!!', end='\n\n')
            parser.print_help(sys.stderr)
            sys.exit(1)
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        # in command line mode (console)
        fe, n, m = process(args, cfg, device)
jacques.grelet_ird.fr's avatar
jacques.grelet_ird.fr committed
        print("Dimensions: {} x {}".format(m, n))
        print(fe.disp(args.key))