Esempio n. 1
0
def _prompt_general(header, skeys, sources=None, args=None):
    msg.okay(header)
    for i, k in enumerate(skeys):
        msg.std("{}. {}".format(i, k))
    msg.blank(1,0)
    choice = input("Selection: ")
    if re.match("[\d]+", choice.strip()):
        value = int(choice)
        if sources is None:
            return value
        else:
            if value in sources:
                sources[value](*args)
            else:
                msg.warn("choice '{}' not in list of possibilities.".format(choice))           
    else:
        msg.warn("invalid (non-numeric) choice: '{}'".format(choice))           
Esempio n. 2
0
def prompt_output(wizard, parameter, auto=True):
    """Prompts for the setting up of model output for the specified parameter.
    """
    target = _find_target(wizard, parameter)
    if not auto:
        #Give the user the option of overriding previous choices.
        if target.compareto is not None:
            msg.gen("This parameter is already being compared to model output.")
            remodel = wizard.input("Would you like to re-specify the details?")[0].lower() == 'y'
            msg.blank(1,0)
        else:
            remodel = True
    else:
        #We only care about getting new things that we haven't got already
        remodel = target.compareto is None

    if remodel:
        _prompt_model(wizard, parameter, target)
Esempio n. 3
0
def prompt_target(wizard, parameter, auto=True):
    """Prompts the user whether to save the output parameter's values to file.
    """
    target = _find_target(wizard, parameter)
    if not auto:
        #Give the user the option of overriding previous choices.
        if target is not None:
            msg.gen("This parameter is being saved already.")
            retarg = wizard.input("Would you like to re-specify the details?")[0].lower() == 'y'
            msg.blank(1,0)
        else:
            retarg = True
    else:
        #We only care about getting new things that we haven't got already
        retarg = target is None

    if retarg:
        _prompt_target(wizard, parameter, target)    
Esempio n. 4
0
def prompt_input(wizard, parameter):
    """Prompts for the location of the input for the specified parameter.
    """
    if _has_input(wizard, parameter):
        msg.gen("This parameter has input specified already.")
        reset = wizard.input("Would you like to add another? ").lower()[0] == 'y'
        if not reset:
            return
        else:
            msg.blank(1,0)

    skeys = ["Unit Test Output", "Existing File", "Known Function", "Constant"]
    sources = {
        0: _input_testsource,
        1: _input_existing,
        2: _input_function,
        3: _input_constant,
    }
    _prompt_general("Choose an input source:", skeys, sources, (wizard, parameter))
Esempio n. 5
0
    def _compile(self, dirpath, makename, compiler, debug, profile):
        """Compiles the makefile at the specified location with 'compiler'.

        :arg dirpath: the full path to the directory where the makefile lives.
        :arg compiler: one of ['ifort', 'gfortran'].
        :arg makename: the name of the make file to compile.
        """
        from os import path
        options = ""
        if debug:
            options += " DEBUG=true"
        if profile:
            options += " GPROF=true"

        from os import system
        codestr = "cd {}; make -f '{}' F90={} FAM={}" + options
        code = system(codestr.format(dirpath, makename, compiler, compiler[0]))

        #It turns out that the compiler still returns a code of zero, even if the compile
        #failed because the actual compiler didn't fail; it did its job properly. We need to
        #check for the existence of errors in the 'compile.log' file.
        lcount = 0
        errors = []
        log = path.join(dirpath, "compile.log")
        with open(log) as f:
            for line in f:
                lcount += 1
                if lcount > 21 and lcount < 32:
                    errors.append(line)
                elif lcount > 21:
                    break

        if len(errors) > 0:
            #There are 21 lines in the compile.log file when everything runs correctly
            #Overwrite code with a bad exit value since we have some other problems.
            code = 1
            #We want to write the first couple of errors to the console and give them the
            #option to still execute if the compile only generated warnings.
            msg.warn("compile generated some errors or warnings:")
            msg.blank()
            msg.info(''.join(errors))

        return code
Esempio n. 6
0
    def _compile(self, dirpath, makename, compiler, debug, profile):
        """Compiles the makefile at the specified location with 'compiler'.

        :arg dirpath: the full path to the directory where the makefile lives.
        :arg compiler: one of ['ifort', 'gfortran'].
        :arg makename: the name of the make file to compile.
        """
        from os import path
        options = ""
        if debug:
            options += " DEBUG=true"
        if profile:
            options += " GPROF=true"

        from os import system
        codestr = "cd {}; make -f '{}' F90={} FAM={}" + options
        code = system(codestr.format(dirpath, makename, compiler, compiler[0]))

        #It turns out that the compiler still returns a code of zero, even if the compile
        #failed because the actual compiler didn't fail; it did its job properly. We need to
        #check for the existence of errors in the 'compile.log' file.
        lcount = 0
        errors = []
        log = path.join(dirpath, "compile.log")
        with open(log) as f:
            for line in f:
                lcount += 1
                if lcount > 21 and lcount < 32:
                    errors.append(line)
                elif lcount > 21:
                    break

        if len(errors) > 0:
            #There are 21 lines in the compile.log file when everything runs correctly
            #Overwrite code with a bad exit value since we have some other problems.
            code = 1
            #We want to write the first couple of errors to the console and give them the
            #option to still execute if the compile only generated warnings.
            msg.warn("compile generated some errors or warnings:")
            msg.blank()
            msg.info(''.join(errors))

        return code
Esempio n. 7
0
def _prompt_model(wizard, parameter, target):
    """Prompts the user for details about the model output for comparison.
    """
    #This is essentially the prompt to setup the <output> tags. Look for the existing
    #<output> in the test specification.
    if target.compareto is None or target.compareto is not in wizard.tauto.outputs:
        from xml.etree.ElementTree import Element
        output = Element("output", {"identifier": "{}.auto".format(target.name)})
        newoutput = True
    else:
        output = wizard.tauto.outputs[target.compareto].xml
        newoutput = False

    skeys = ["Automate.", "Set a constant value.", "Don't compare to model output."]
    choice = _prompt_general("Choose the source of the model output:", skeys)
    attribs = {
        "tolerance": {"leader": "Enter % accuracy required for comparisons: 0.0 to 1.0 (default)?",
                      "cast": float}
    }
    #Keep track of whether we actually need to set model output for this parameter.
    skip = choice == 2
    
    if choice == 0:
        #The biggest problem we have here is that we need to specify the file to use
        #for the model output. We could have the user search for one, but really the
        #way this works is that we need to compile the test, run it without checks and
        #then present the user with the output to verify for each test case. Since the
        #automator presents the input parameters first and then allows the targets to
        #be established without model outputs first, we should be able to compile and
        #run the test (if it hasn't been done already).
        rdict = {
            1: _examine_output,
            2: _print_outpath,
            3: _start_debug,
            4: _set_correct,
            5: _set_existing
        }
        rkeys = ["Re-run the tests to re-create output(s).",
                 "Examine the variables' output(s) for correctness.",
                 "Print the location of the model output(s).",
                 "Start the debugger for the unit test program.",
                 "Set the variable output(s) as correct.",
                 "Specify an existing file as model output.",
                 "Exit the correction loop."]
        varfile = None
        correct = True
        runonce = False

        while correct:
            msg.blank()
            if has_outputs(wizard, True):
                rchoice = _prompt_general("The model output for the active test case exists.\n"
                                          "What would you like to do?", rkeys)
                if rchoice in rdict:
                    varfile = rdict[rchoice](wizard, parameter, target)
                    if rchoice == 4:
                        correct = False
                elif rchoice == 0:
                    run(wizard, True, True)
                elif rchoice == 5:
                    correct = False
            else:
                #First run the tests to generate the output, then present it to the user
                #so that they can check it is right.
                if not runonce:
                    msg.info("Running the unit test to generate output for examination.")
                    run(wizard, False, True)
                    runonce = True
                else:
                    msg.warn("the model outputs weren't generated by running the unit test.\n"
                             "Check error messages.")
                    correct = False
            
        if varfile is not None:
            output.set("file", varfile)
                
        if "autoclass" in target.xml.attrib and target.xml.attrib["autoclass"] == "true":
            output.set("autoclass", "true")
            if "tolerance" in selattrs:
                output.set("actolerance", selattrs["tolerance"])
    elif choice == 1:
        attribs["value"] = {"leader": "Enter the correct value; can be any valid python code."}

    if skip:
        #We need to remove an output if one already exists; otherwise do nothing.
        if target.compareto is not None:
            if target.compareto in wizard.tauto.outputs:
                del wizard.tauto.outputs[target.compareto]
            target.compareto = None
    else:
        #Prompts for the last, sundry attributes on the <output> tag.
        selattrs = _prompt_attributes("output", attribs)
        for k, v in selattrs.items():
            output.set(k, v)
            
        if newoutput:
            target.compareto = output.attrib["identifier"]
            wizard.tauto.outputs[target.compareto] = TestOutput(output)
Esempio n. 8
0
def compile(folder, compiler=None, identifier=None, debug=False, profile=False,
            quiet=False, moptions=None, inclfortpy=True, vupdates=None,
            strict=False, inclfpyaux=False):
    """Runs the makefile in the specified folder to compile the 'all' rule.

    :arg vupdates: a list of module names for which the output .mod and .o files
      should have version information attached.
    """
    if inclfortpy:
        #Before we can compile the library, we need to make sure that we have a fortpy
        #.mod and .o compiled with the *same* compiler version specified.
        from fortpy.utility import get_fortpy_templates_dir
        _ensure_fileversion(compiler, "fortpy", get_fortpy_templates_dir(), folder)
        
    options = ""
    if debug:
        options += " DEBUG=true"
    if profile:
        options += " GPROF=true"
    if strict:
        options += " STRICT=true"    

    if moptions is not None:
        for opt in moptions:
            options += " {}".format(opt)
        
    if identifier is not None:
        codestr = "cd {}; make -f 'Makefile.{}' F90='{}' FAM='{}'" + options
        command = codestr.format(folder, identifier, executor(compiler), family(compiler))
    else:
        codestr = "cd {}; make F90='{}' FAM='{}'" + options
        command = codestr.format(folder, executor(compiler), family(compiler))
        
    #If we are running in quiet mode, we don't want the compile information
    #to post to stdout; only errors should be redirected. This means we need
    #to wrap the execution in a subprocess and redirect the std* to PIPE
    from os import waitpid, path
    from subprocess import Popen, PIPE
    pcompile = Popen(command, shell=True, executable="/bin/bash", stdout=PIPE, stderr=PIPE)
    waitpid(pcompile.pid, 0)
    
    if not quiet:
        output = [x.decode('utf8') for x in pcompile.stdout.readlines()]
        msg.std(''.join(output))
    #else: #We don't need to get these lines since we are purposefully redirecting them.
    error = [x.decode('utf8') for x in pcompile.stderr.readlines()]
    code = len(error)
    if code != 0:
        msg.err(''.join(error))

    #It turns out that the compiler still returns a code of zero, even if the compile
    #failed because the actual compiler didn't fail; it did its job properly. We need to
    #check for the existence of errors in the 'compile.log' file.
    lcount = 0
    errors = []
    log = path.join(folder, "compile.log")
    with open(log) as f:
        for line in f:
            lcount += 1
            if lcount > 21 and lcount < 32:
                errors.append(line)
            elif lcount > 21:
                break

    if len(errors) > 0:
        #There are 21 lines in the compile.log file when everything runs correctly
        #Overwrite code with a bad exit value since we have some other problems.
        code = 1
        #We want to write the first couple of errors to the console and give them the
        #option to still execute if the compile only generated warnings.
        msg.warn("compile generated some errors or warnings:")
        msg.blank()
        msg.info(''.join(errors))

    if vupdates is not None:
        for modname in vupdates:
            _vupdate_compiled_module(compiler, modname, folder, rename=False)
        
    return (code, len(errors)==0)
Esempio n. 9
0
def compile(folder,
            compiler=None,
            identifier=None,
            debug=False,
            profile=False,
            quiet=False,
            moptions=None,
            inclfortpy=True,
            vupdates=None,
            strict=False,
            inclfpyaux=False):
    """Runs the makefile in the specified folder to compile the 'all' rule.

    :arg vupdates: a list of module names for which the output .mod and .o files
      should have version information attached.
    """
    if inclfortpy:
        #Before we can compile the library, we need to make sure that we have a fortpy
        #.mod and .o compiled with the *same* compiler version specified.
        from fortpy.utility import get_fortpy_templates_dir
        _ensure_fileversion(compiler, "fortpy", get_fortpy_templates_dir(),
                            folder)

    options = ""
    if debug:
        options += " DEBUG=true"
    if profile:
        options += " GPROF=true"
    if strict:
        options += " STRICT=true"

    if moptions is not None:
        for opt in moptions:
            options += " {}".format(opt)

    if identifier is not None:
        codestr = "cd {}; make -f 'Makefile.{}' F90='{}' FAM='{}'" + options
        command = codestr.format(folder, identifier, executor(compiler),
                                 family(compiler))
    else:
        codestr = "cd {}; make F90='{}' FAM='{}'" + options
        command = codestr.format(folder, executor(compiler), family(compiler))

    #If we are running in quiet mode, we don't want the compile information
    #to post to stdout; only errors should be redirected. This means we need
    #to wrap the execution in a subprocess and redirect the std* to PIPE
    from os import waitpid, path
    from subprocess import Popen, PIPE
    pcompile = Popen(command,
                     shell=True,
                     executable="/bin/bash",
                     stdout=PIPE,
                     stderr=PIPE,
                     close_fds=True)
    waitpid(pcompile.pid, 0)

    if not quiet:
        output = [x.decode('utf8') for x in pcompile.stdout.readlines()]
        msg.std(''.join(output))
    #else: #We don't need to get these lines since we are purposefully redirecting them.
    error = [x.decode('utf8') for x in pcompile.stderr.readlines()]
    code = len(error)
    if code != 0:
        msg.err(''.join(error))

    pcompile.stdout.close()
    pcompile.stderr.close()
    #It turns out that the compiler still returns a code of zero, even if the compile
    #failed because the actual compiler didn't fail; it did its job properly. We need to
    #check for the existence of errors in the 'compile.log' file.
    lcount = 0
    errors = []
    log = path.join(
        folder, "compile.{}.log".format(
            identifier if identifier is not None else "default"))
    with open(log) as f:
        for line in f:
            lcount += 1
            if lcount > 21 and lcount < 32:
                errors.append(line)
            elif lcount > 21:
                break

    if len(errors) > 0:
        #There are 21 lines in the compile.log file when everything runs correctly
        #Overwrite code with a bad exit value since we have some other problems.
        code = 1
        #We want to write the first couple of errors to the console and give them the
        #option to still execute if the compile only generated warnings.
        msg.warn("compile generated some errors or warnings:")
        msg.blank()
        msg.info(''.join(errors))

    if vupdates is not None:
        for modname in vupdates:
            _vupdate_compiled_module(compiler, modname, folder, rename=False)

    return (code, len(errors) == 0)