import logging
import os
import pwd
from validphys import hyperplottemplates
from validphys.app import App
from validphys.loader import HyperscanNotFound, Loader
from validphys.utils import yaml_safe
log = logging.getLogger(__name__)
[docs]class HyperoptPlotApp(App):
[docs]    def add_positional_arguments(self, parser):
        """Wrapper around argumentparser"""
        # Hyperopt settings
        parser.add_argument(
            "hyperopt_name", help="Folder of the hyperopt fit to generate the report for"
        )
        parser.add_argument(
            "-l",
            "--loss_target",
            help="Choice for the definition of target loss",
            choices=['average', 'best_worst', 'std'],
            default='average',
        )
        parser.add_argument(
            "-v",
            "--val_multiplier",
            help="Fraction to weight the validation loss with (test_multiplier = 1-val_multiplier)",
            type=float,
            default=0.0,
        )
        parser.add_argument(
            "-if",
            "--include_failures",
            help="Flag to include failed runs in  the plots",
            action="store_true",
        )
        parser.add_argument(
            "-t",
            "--threshold",
            help="Value of the loss function from which to consider a run to have failed",
            type=float,
            default=1e3,
        )
        parser.add_argument(
            "-f",
            "--filter",
            help="Add the filter key=value to the dataframe",
            nargs="+",
            default=(),
        )
        parser.add_argument(
            "-c",
            "--combine",
            help="If more than one replica folder is found, combine all trials",
            action="store_true",
        )
        # Autofiltering
        parser.add_argument(
            "--autofilter",
            help="Given a number of keys, perform an autofilter (removing combinations of elements with worse rewards",
            nargs="+",
        )
        # Debugging
        parser.add_argument("--debug", help="Print debug information", action="store_true")
        # Report meta data
        parser.add_argument(
            "--author",
            help="Add custom author name to the report's meta data",
            type=str,
            default=pwd.getpwuid(os.getuid())[4].replace(",", ""),
        )
        parser.add_argument("--title", help="Add custom title to the report's meta data", type=str)
        parser.add_argument(
            "--keywords",
            help="Add keywords to the report's meta data. The keywords must be provided as a list",
            type=list,
            default=[],
        )
        args = parser.parse_args() 
[docs]    def complete_mapping(self):
        args = self.args
        hyperop_name = args["hyperopt_name"]
        ll = Loader()
        try:
            hyperop_spec = ll.check_hyperscan(hyperop_name)
            hyperop_folder = hyperop_spec.path.as_posix()
        except HyperscanNotFound as e:
            log.error(e)
            log.warning("No hyperscan of '%s' found, falling back to old behaviour", hyperop_name)
            hyperop_folder = hyperop_name
        hyperopt_filter = f"{hyperop_folder}/filter.yml"
        while hyperop_folder[-1] == "/":
            hyperop_folder = hyperop_folder[:-1]
        with open(hyperopt_filter) as f:
            filtercard = yaml_safe.load(f)
        folder_path = hyperop_folder
        index_slash = folder_path.rfind("/") + 1
        name_folder = folder_path[index_slash:]
        if args['title'] == None:
            args["title"] = f"NNPDF hyperoptimization report for {name_folder}"
        autosettings = {}
        autosettings["meta"] = {
            "title": args["title"],
            "author": args["author"],
            "keywords": args["keywords"],
        }
        autosettings["commandline_args"] = {
            "hyperopt_folder": hyperop_folder,
            "val_multiplier": args["val_multiplier"],
            "include_failures": args["include_failures"],
            "threshold": args["threshold"],
            "filter": args["filter"],
            "combine": args["combine"],
            "autofilter": args["autofilter"],
            "debug": args["debug"],
            "loss_target": args["loss_target"],
        }
        try:
            autosettings["hyperscan_config"] = filtercard["hyperscan_config"]
        except KeyError:
            # Work with the older hyperscan runs
            autosettings["hyperscan_config"] = filtercard["hyperscan"]
        return autosettings 
[docs]    def get_commandline_arguments(self, cmdline=None):
        args = super().get_commandline_arguments(cmdline)
        args['config_yml'] = hyperplottemplates.template_path
        return args 
[docs]    def get_config(self):
        # No error handling here because this is our internal file
        with open(self.args['config_yml']) as f:
            # TODO: Ideally this would load round trip but needs
            # to be fixed in reportengine.
            c = yaml_safe.load(f)
        c.update(self.complete_mapping())
        return self.config_class(c, environment=self.environment)  
[docs]def main():
    app = HyperoptPlotApp()
    app.main() 
if __name__ == "__main__":
    main()