示例#1
0
def sk_layout(args):
    """Manipulate the tab order in resulting htmls by changing
    the order of keys of 'analysis' dict in scikick.yml.
    """
    skconf = ScikickConfig(need_pages=True)
    tabs = get_tabs(skconf)
    # modify the layout of a submenu
    if args.submenu is not None:
        if args.submenu[0] not in tabs:
            reterr(f"sk: Error: No menu named \"{args.submenu[0]}\"")
        if len(args.order) != 0:
            skconf = rearrange_submenus(args.submenu[0], args.order, skconf,
                                        tabs)
            yaml_dump(skconf.config)
        tabs = get_tabs(skconf)
        submenu_contents = tabs[args.submenu[0]]
        submenu_text = list(
            map(lambda r: os.path.basename(r), submenu_contents))
        for i in range(len(submenu_text)):
            print(f"{i + 1}:  {submenu_text[i]}")
    else:
        if len(args.order) != 0:
            skconf = rearrange_tabs(args.order, skconf, tabs)
            yaml_dump(skconf.config)
        # print layout
        tabs = get_tabs(skconf)
        for i in range(len(tabs.keys())):
            print(f"{i + 1}:  {list(tabs.keys())[i]}")
示例#2
0
def site(args):
    """Adds the custom link to the 'More' tab"""
    ymli = yaml_in()
    if "site" not in ymli.keys():
        ymli["site"] = dict()
    # print the links
    if args.get:
        for k in ymli["site"].keys():
            print(f"{k} => {ymli['site'][k]}")
        return
    if args.delete and args.name is None:
        reterr("sk: Error: '--name' has to be specified for deletion")
    if args.delete:
        # handle deletion
        del_ret = ymli["site"].pop(args.name[0], None)
        if del_ret is not None:
            print(f"sk: Removed link named '{args.name[0]}'")
        else:
            print(f"sk: Link '{args.name[0]}' not found")
        yaml_dump(ymli)
        return
    if (args.name is None) or (args.link is None):
        reterr("sk: Error: both '--name' and '--link' have to be specified")
    ymli["site"][args.name[0]] = args.link[0]
    print(f"sk: Added link {args.link[0]} under {args.name[0]}")
    yaml_dump(ymli)
示例#3
0
def run_sk_dryrun(snakefile=get_sk_snakefile(), workdir=os.getcwd()):
    # get snakemake --dryrun output with --reason
    # TODO - use python API
    status = subprocess.run(
        ["snakemake", "--snakefile", snakefile, \
            "--directory", workdir, \
            "--dryrun", "--reason"], \
        stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
    if status.returncode != 0:
        warn("sk: There was an error in snakemake --dry-run, see below")
        reterr(status.stdout.decode("utf-8"))

    stdout = status.stdout.decode("utf-8").split("\n")
    # Filter output for job/reason outputs only
    stdout = list(
        filter(
            lambda l: re.match(job_pattern, l) is not None or re.match(
                reason_pattern, l) is not None, stdout))

    # Prevent status from return is something goes wrong
    #assert status.returncode == 0, "snakemake dryrun failed"

    # get "Job..." and "Reason:..." line pairs
    jobs = list(map(lambda i: stdout[i * 2], range(0, int(len(stdout) / 2))))
    reasons = list(
        map(lambda i: stdout[i * 2 + 1], range(0, int(len(stdout) / 2))))
    return jobs, reasons
示例#4
0
 def report_dir(self):
     """Get the value of 'reportdir' from scikick.yml"""
     if self.config['reportdir'] is None:
         reterr(
             "sk: Error: Report directory (reportdir) has not been set in scikick.yml"
         )
         # Eventually it may be safe to set this value dynamically
         #warn("sk: Warning: Setting reportdir to 'report' and writing to scikick.yml")
         #self.config['reportdir'] = "report"
         # yaml_dump may be unsafe if self.config has been changed elsewhere
         # A direct modification of reportdir would be better
         # yaml_dump(self.config)
     return os.path.normpath(self.config['reportdir'])
示例#5
0
def new_tab_order(args_order, tab_keys):
    """Get the new order of tabs based on the user input.
    Expands the user provided order to the full explicit index order.
    Returns a list of indices, which would be used to reorder the
    'analysis' keys in scikick.yml
    args_order -- order provided by the user (list of indices as strings)
    tabs -- list of tab names
    """
    # in case 9 or less tabs, the the order can be without spaces
    if len(args_order) == 1:
        order = list(map(lambda x: int(x) - 1, str(args_order[0])))
    else:
        order = list(map(lambda x: x - 1, args_order))
    if len(set(order)) == len(order) and \
            len(order) <= len(tab_keys) and \
            min(order) >= 0 and max(order) < len(tab_keys):
        # fill the rest of idxs if not all provided
        for i in range(len(tab_keys)):
            if i not in order:
                order.append(i)
        return order
    else:
        reterr("sk: Error: Inputs must be a unique list of tab indices")
示例#6
0
def yaml_in(ymlpath='scikick.yml', need_pages=False):
    """Read scikick.yml.
    Returns an ordereddict.
    need_pages -- logical, whether to error if analysis is empty
    """
    #Exit with an error message if scikick.yml is not found
    if not os.path.isfile(ymlpath):
        reterr(f"sk: Error: {ymlpath} not found," + \
               "to get a template, run\nsk: sk init")

    ymli = yaml.YAML()
    ymli = ymli.load(open(ymlpath, "r"))

    if ymli is None:
        warn("sk: Warning: scikick.yml is empty")
        ymli = dict()

    ## Checks that will be modified for this read-in only
    # make sure that mandatory fields are present
    if "analysis" not in ymli.keys():
        if need_pages:
            reterr("sk: Error: no pages have been added to scikick.yml, " + \
                "this can be done with\nsk: sk add my.rmd")
        else:
            warn("sk: Warning: scikick.yml is missing analysis field")
            ymli["analysis"] = ordereddict()
    else:
        if ymli["analysis"] is None:
            ymli["analysis"] = ordereddict()
        if len(ymli["analysis"]) == 0:
            if need_pages:
                reterr("sk: Error: no pages have been added to scikick.yml, " + \
                    "this can be done with\nsk: sk add my.rmd")
            else:
                ymli["analysis"] = ordereddict()

    if "reportdir" not in ymli.keys():
        warn("sk: Warning: scikick.yml is missing reportdir field")
        ymli["reportdir"] = ""

    return ymli
示例#7
0
def sk_move_check(src, dest):
    """Perform checks on src and dest
    and quit if bad arguments are given
    src -- list of files to move
    des -- list containing the file/dir to move to
    """
    config = yaml_in()
    for s in src:
        if not os.path.exists(s):
            reterr(f"sk: Error: file or directory {s} doesn't exist")
    if len(src) > 1:
        if not os.path.isdir(dest[0]):
            reterr("sk: Error: moving multiple files to a single one")
    elif len(src) == 1 and (not os.path.isdir(dest[0])):
        old_ext = os.path.splitext(src[0])[1]
        new_ext = os.path.splitext(dest[0])[1]
        if old_ext.lower() != new_ext.lower():
            warn("sk: Warning: changing file extension")
        if (src[0] in config["analysis"].keys()) and \
            (new_ext.lower() not in map(str.lower, supported_extensions)):
            reterr(
                f"sk: Error: only extensions {', '.join(supported_extensions)} are supported ({new_ext} given)"
            )
示例#8
0
def add(files, deps=list(), force=False, copy_deps=None):
    """ Add files and dependencies to them
    files -- page file list
    deps -- dependency file list
    force -- bool whether to add additional index files
    copy_deps -- file to copy dependencies from
    """
    if deps is None:
        deps = list()
    ymli = yaml_in()
    if copy_deps is not None:
        # copy_deps(src,dest)
        copy_deps = copy_deps[0]
        if copy_deps not in ymli["analysis"]:
            reterr(f"sk: Error: file {copy_deps} is not included")
        deps2copy = ymli["analysis"][copy_deps]
        if not ((deps2copy is None) or (len(deps2copy) == 0)):
            deps = list(set(deps + deps2copy))
            warn(f"sk: Copying {copy_deps} dependencies")
        else:
            warn(f"sk: Warning: {copy_deps} has no dependencies")
    # add files
    for fname in files:
        # Add script
        # Should the script be added?
        add_fname = add_check(fname, ymli, force, deps)
        if add_fname:
            # add near scripts in the same directory
            if len(ymli["analysis"].keys()) > 0:
                commpath = os.path.commonpath(list(ymli["analysis"].keys()))
            else:
                commpath = ""
            tab_name = os.path.dirname(rm_commdir(fname, commpath))
            all_tabs = list(
                map(lambda f: os.path.dirname(rm_commdir(f, commpath)),
                    ymli["analysis"].keys()))
            tab_matches = list(
                filter(lambda i: all_tabs[i] == tab_name,
                       range(len(all_tabs))))
            if (tab_name != "") and (len(tab_matches) != 0):
                ymli["analysis"].insert(tab_matches[-1] + 1, fname, [])
            else:
                ymli['analysis'][fname] = None
            warn(f"sk: Added {fname}")
        # Add dependencies
        for dep in deps:
            # Should the dep be added?
            add_dep = add_dep_checks(fname, ymli, force, dep)
            if add_dep:
                if ymli['analysis'][fname] is None:
                    ymli['analysis'][fname] = []
                ymli['analysis'][fname].append(dep)
                warn(f"sk: Added dependency {dep} to {fname}")
                if dep in ymli["analysis"].keys():
                    warn(
                        f"sk:   {fname} will be executed after any executions of {dep}"
                    )
                else:
                    warn(
                        f"sk:   {fname} will be executed after any modifications to {dep}"
                    )
    yaml_dump(ymli)
示例#9
0
def add_check(fname, ymli, force, deps):
    """Performs a check if fname can be added to scikick.yml as a key"""
    pages = ymli["analysis"].keys()
    if fname in pages:
        warn(f"sk: Found existing entry for {fname}")
        return False
    # filenames cannot currently have wildcard symbols
    if True in [i in fname for i in wildcard_symbols]:
        warn(
            f"sk: Error: Filename ({fname}) cannot have wildcard symbols ({' '.join(wildcard_symbols)})"
        )
        return False
        # check if the file extension is supported
    fext = os.path.splitext(fname)[-1]
    if fext.lower() == ".ipynb":
        warn(
            "sk: Warning: .ipynb use in Scikick is experimental and requires installation of jupyter"
        )
    f_exe_support = fext.lower() in [x.lower() for x in supported_extensions]
    if not f_exe_support:
        extension_list_str = ', '.join(supported_extensions)
        warn("sk: Error: Only %s files can be added as pages (%s)" % \
            (extension_list_str, fname))
        return False
    # error if the directory doesn't exist
    dirname = os.path.dirname(fname)
    if dirname != "":
        if not os.path.isdir(dirname):
            reterr(f"sk: Error: Directory {dirname} does not exist.")
    # create the file if it doesn't exist
    if not os.path.isfile(fname):
        warn(f"sk: Warning: File {fname} doesn't exist")
        warn(f"sk: Creating new file {fname}")
        open(fname, "a").close()
    if fname not in pages:
        # Check for other files with same basename (and therefore same md output file)
        fname_base = os.path.splitext(fname)[0]
        page_basenames = map(lambda x: os.path.splitext(x)[0], pages)
        page_basename_exists = fname_base in page_basenames
        if page_basename_exists:
            warn(
                f"sk: Error: Page {fname_base} is already to be compiled from another file."
            )
            return False
        # check for "index.Rmd"s
        index_list = get_indexes(ymli)
        if os.path.splitext(os.path.basename(fname))[0] == "index":
            if len(index_list) == 0:
                warn(
                    f"sk: An index file {fname} has been added and will be used as the homepage"
                )
                # touch the added index file to ensure execution
                os.utime(fname, None)
            elif len(index_list) == 1:
                if not force:
                    reterr(f"sk: Error: An index file {index_list[0]} already exists\n" + \
                        "sk: Error: An additional one can be added, but neither will be used as a homepage\n" + \
                        f"sk: Error: To persist, use 'sk add --force {fname}'")
                else:
                    warn(
                        f"sk: Warning: A redundant index file has been added\n"
                        +
                        "sk: Warning: Neither of the added index files will be used as a homepage"
                    )
                    os.utime(
                        os.path.join(get_sk_exe_dir(), "workflow",
                                     "notebook_rules", "index.Rmd"), None)
            elif len(index_list) > 1:
                warn(
                    f"sk: Warning: A redundant index file has been added\n" +
                    "sk: Warning: Neither of the added index files will be used as a homepage"
                )
    return True
示例#10
0
 def analysis(self):
     """Get 'analysis:' dict from scikick.yml"""
     if self.config['analysis'] is not None:
         return self.config['analysis']
     reterr("No analysis field found in scikick config")
     return None