Source on GitHub

Module paroxython.cli_recommend

Read and execute a pipeline of commands and report the learning costs.

Usage

paroxython recommend [options] DB_PATH

Description

Requires an existing database previously generated by the command:

    paroxython collect DIRECTORY

... and a pipeline of commands describing which concepts (taxa) are
already known, which ones need to be illustrated or must be avoided. By
default, it results in a list of recommended programs, along with their
total learning costs and the individual learning cost of each of the
concepts they feature. These results are presented in Markdown format.
With the option `-o stdout` the program list is simply printed to stdout.

Shortcut

For DB_PATH, instead of the path of a tag database, you can provide the
DIRECTORY previously collected. Paroxython will automatically look for the
tag database at DIRECTORY/../DIRECTORY_db.json.

Options

-b --base=PATH      Value accessible, with the syntax "{base}", by any shell
                    command of the pipeline. If not specified, this is the
                    parent directory of DB_PATH. [default: ]
-c --cost=STR       Learning cost assessment strategy. [default: zeno]
                    Currently available:
                    • zeno: the i-th edge of a taxon, if not already
                            imparted, costs 2^(-i). For instance, the taxon
                            old/new/new will costs 2^-2 + 2^-3 = 0.375.
                    • linear: simply count the number of new edges.
-o --output=PATH    The path of the resulting report. If it is omitted, a
                    value of PREFIX_recommendations.md is inferred from the
                    path PREFIX_db.json of DB_PATH. If it is STDOUT, the
                    sorted list of recommended (but not hidden) programs, is
                    printed on the standard output. [default: ]
-p --pipe=PATH      Path of the command pipeline. If it is omitted, a value
                    of PREFIX_pipe.py is inferred from the path
                    PREFIX_db.json of DB_PATH. If is is <code>\[]</code>, no filter is
                    applied. [default: ]
-f --format=STR     The format of program titles in the report. This string
                    can contains the following identifiers (between braces):
                    • name: filename of the program.
                    • path: program key in the DB "programs" dictionary.
                    • prefix: name of DB_PATH, minus any "_db.json" suffix.
                    • absolute: absolute path to DB_PATH's parent folder.
                    • relative: relative path to DB_PATH's parent folder.
                    Shortcut: if format is "vscode", makes program names to
                        be clickable and opening in VS Code.
                    [default: `{name}`]

Example

Use `-o stdout` to pipe the results into another shell command. For instance,
let's assume that:

- your program repository is `path/to/programs`;
- your tag database is at its default location `path/to/programs_db.json`;
- your pipeline is at its default location `path/to/programs_pipe.py`.

Then, to copy (not move) all the recommended programs to an existing
directory DEST, just do:

paroxython recommend -o stdout path/to/programs_db.json \
    | xargs  -I {} sh -c "cp path/to/programs/{} DEST"
Expand source code Browse GitHub
import json
import sys
from pathlib import Path

import regex  # type: ignore
from ast import literal_eval

from .goodies import print_success, print_exit
from .recommend_programs import Recommendations


def cli_wrapper(args):
    db_path = Path(args["DB_PATH"])
    if not db_path.exists():
        print_exit(f"no file or directory at '{db_path.absolute()}': aborted.")
    parent_path = db_path.parent
    if db_path.is_dir():
        for suffix in ("_db", "-db"):
            db_path = parent_path / f"{db_path.name}{suffix}.json"
            if db_path.is_file():
                print(f"Using database '{db_path}'.")
                break
        else:
            print_exit(f"unable to locate a tag database in '{parent_path}': aborted.")
    m = regex.fullmatch(r"(.+[_-])db\.json", db_path.name)
    prefix = m[1] if m else ""
    pipeline_path = Path(args["--pipe"] or parent_path / f"{prefix}pipe.py")
    if pipeline_path.is_file():
        print(f"Using pipeline '{pipeline_path}'.")
        try:
            commands = literal_eval(pipeline_path.read_text())
        except Exception:  # Too many possible exceptions
            print_exit(f"Malformed pipeline: aborted.")
    elif args["--pipe"] == "[]":
        print("Using an empty pipeline.")
        commands = []
    else:
        print_exit(f"No pipeline at '{pipeline_path}': aborted.")
    stdout_backup = sys.stdout
    if args["--output"].upper() == "STDOUT":
        sys.stdout = sys.stderr
    title_format = args["--format"]
    if title_format.lower() == "vscode":
        title_format = "[`{name}`](vscode://file/{absolute}/{prefix}/{path})"
    title_format = title_format.format(
        name="{name}",
        path="{path}",
        prefix=prefix.rstrip("_-"),
        absolute=parent_path.resolve(),
        relative=parent_path,
    )
    rec = Recommendations(
        db=json.loads(db_path.read_text()),
        base_path=Path(args["--base"] or parent_path),
        assessment_strategy=args["--cost"],
        title_format=title_format,
    )
    rec.run_pipeline(commands)
    if args["--output"].upper() == "STDOUT":
        sys.stdout = stdout_backup
        return print("\n".join(sorted(rec.selected_programs - rec.hidden_programs)))
    output_path = Path(args["--output"] or parent_path / f"{prefix}recommendations.md")
    output_path.write_text(rec.get_markdown())
    print_success(f"Dumped: {output_path.resolve()}\n")

Functions

def cli_wrapper(args)
Expand source code Browse GitHub
def cli_wrapper(args):
    db_path = Path(args["DB_PATH"])
    if not db_path.exists():
        print_exit(f"no file or directory at '{db_path.absolute()}': aborted.")
    parent_path = db_path.parent
    if db_path.is_dir():
        for suffix in ("_db", "-db"):
            db_path = parent_path / f"{db_path.name}{suffix}.json"
            if db_path.is_file():
                print(f"Using database '{db_path}'.")
                break
        else:
            print_exit(f"unable to locate a tag database in '{parent_path}': aborted.")
    m = regex.fullmatch(r"(.+[_-])db\.json", db_path.name)
    prefix = m[1] if m else ""
    pipeline_path = Path(args["--pipe"] or parent_path / f"{prefix}pipe.py")
    if pipeline_path.is_file():
        print(f"Using pipeline '{pipeline_path}'.")
        try:
            commands = literal_eval(pipeline_path.read_text())
        except Exception:  # Too many possible exceptions
            print_exit(f"Malformed pipeline: aborted.")
    elif args["--pipe"] == "[]":
        print("Using an empty pipeline.")
        commands = []
    else:
        print_exit(f"No pipeline at '{pipeline_path}': aborted.")
    stdout_backup = sys.stdout
    if args["--output"].upper() == "STDOUT":
        sys.stdout = sys.stderr
    title_format = args["--format"]
    if title_format.lower() == "vscode":
        title_format = "[`{name}`](vscode://file/{absolute}/{prefix}/{path})"
    title_format = title_format.format(
        name="{name}",
        path="{path}",
        prefix=prefix.rstrip("_-"),
        absolute=parent_path.resolve(),
        relative=parent_path,
    )
    rec = Recommendations(
        db=json.loads(db_path.read_text()),
        base_path=Path(args["--base"] or parent_path),
        assessment_strategy=args["--cost"],
        title_format=title_format,
    )
    rec.run_pipeline(commands)
    if args["--output"].upper() == "STDOUT":
        sys.stdout = stdout_backup
        return print("\n".join(sorted(rec.selected_programs - rec.hidden_programs)))
    output_path = Path(args["--output"] or parent_path / f"{prefix}recommendations.md")
    output_path.write_text(rec.get_markdown())
    print_success(f"Dumped: {output_path.resolve()}\n")