[l2.append("") for _ in range(diff)]
    elif len(word2) > len(word1):
        diff = len(word2) - len(word1)
        [l1.append("") for _ in range(diff)]
    results = []
    for i, j in zip(l1, l2):
        if i:
            results.append(i)
        if j:
            results.append(j)
    return "".join(results)


def main2(word1: str, word2: str) -> str:
    diff = ""
    if len(word1) > len(word2):
        diff += word1[len(word2):]
    elif len(word2) > len(word1):
        diff += word2[len(word1):]
    temp = ""
    for i, j in zip(word1, word2):
        temp += i + j
    return temp + diff


if __name__ == "__main__":
    word1 = "abc"
    word2 = "qwerty"
    console.print(main(word1, word2), style="bold green")
    console.print(main2(word1, word2), style="bold red")
Example #2
0
def test_print_sep_end(print_text, result):
    console = Console(record=True, file=StringIO())
    console.print(*print_text, sep="", end="X")
    assert console.file.getvalue() == result
Example #3
0
def test_emoji():
    """Test printing emoji codes."""
    console = Console(file=StringIO())
    console.print(":+1:")
    assert console.file.getvalue() == "👍\n"
Example #4
0
        """Fit the text in to given width by chopping in to lines.

        Args:
            width (int): Maximum characters in a line.

        Returns:
            Lines: List of lines.
        """
        lines: Lines = Lines()
        append = lines.append
        for line in self.split():
            line.set_length(width)
            append(line)
        return lines


if __name__ == "__main__":  # pragma: no cover
    from rich.console import Console

    console = Console()
    t = Text("foo bar", justify="left")
    print(repr(t.wrap(console, 4)))

    test = Text("Vulnerability CVE-2018-6543 detected")

    def get_style(text: str) -> str:
        return f"bold link https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword={text}"

    test.highlight_regex(r"CVE-\d{4}-\d+", get_style)
    console.print(test)
Example #5
0
def main():

    classes = [
        CircleSphere, SquareRect, CubeRect, Trapezoid, Cone, Cylinder,
        NthPolygon, sin, cos, tan, arcsin, arccos, arctan
    ]

    ex = False

    while not ex:

        selection_table = Table(
            title="\nSelect which calculator you would like to use")

        selection_table.add_column("Index",
                                   justify="right",
                                   style="Red",
                                   no_wrap=True)
        selection_table.add_column("Calculator",
                                   justify="right",
                                   style="cyan",
                                   no_wrap=True)

        selection_table.add_row("1", "Circle/Sphere")
        selection_table.add_row("2", "Square/Rectangle")
        selection_table.add_row("3", "Cube/Rectangular Prism")
        selection_table.add_row("4", "Trapezoid")
        selection_table.add_row("5", "Cone")
        selection_table.add_row("6", "Cylinder")
        selection_table.add_row("7", "Polygon (n sides)")
        # selection_table.add_row("8", "Triangle")
        selection_table.add_row("8", "Sine")
        selection_table.add_row("9", "Cosine")
        selection_table.add_row("10", "Tangent")
        selection_table.add_row("11", "Arcsin")
        selection_table.add_row("12", "Arccos")
        selection_table.add_row("13", "Arctan")

        console = Console()
        console.print(selection_table)

        while True:
            try:
                index = int(
                    input(
                        "Type the number of which calculator you want: ")) - 1
                choice = classes[index]
                break
            except:
                print("That is not a valid input, please try again")

        params = inspect.signature(choice)
        params = list(
            str(params).replace(")", "").replace("(", "").split(", "))

        ps = []

        inval = False

        for i in params:
            try:
                if choice in classes[7:] and i == "measure":
                    ps.append(
                        input(
                            "What is the measure type, degrees, or radians (deg, rad): "
                        ))

                    if "deg" not in ps and "rad" not in ps:
                        print("Invalid Input")
                        inval = True
                        break
                else:
                    ps.append(float(input(f"What is the {i}: ")))
            except:
                print("Invalid Input")
                inval = True
                break

        if inval:
            continue

        try:
            obj = choice(*ps)

            print("\n" + str(obj) + "\n")
        except:
            print("Your inputs could not be calculated.")

        t = input(
            "Type 'return' to go back to the home page and anything else to quit: "
        )
        if t != 'return':
            quit(0)

        os.system("clear")
Example #6
0
        new_text = Text("\n").join(new_lines)
        return new_text


if __name__ == "__main__":  # pragma: no cover
    from rich.console import Console

    text = Text(
        """\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"""
    )
    text.highlight_words(["Lorem"], "bold")
    text.highlight_words(["ipsum"], "italic")

    console = Console()
    console.rule("justify='left'")
    console.print(text, style="red")
    console.print()

    console.rule("justify='center'")
    console.print(text, style="green", justify="center")
    console.print()

    console.rule("justify='right'")
    console.print(text, style="blue", justify="right")
    console.print()

    console.rule("justify='full'")
    console.print(text, style="magenta", justify="full")
    console.print()
Example #7
0
                        removeItemfromWishlist(
                            wishlist_dict['wishlist_torrents'][wishlist_index]['id'])
                    elif user_input == 2:
                        # code for download
                        global torrent_title
                        wishlist_index = int(
                            input("Enter index to download\n")) - 1
                        torrent_title = wishlist_dict['wishlist_torrents'][wishlist_index]['title']
                        DownloadTorrentFromWishlist(
                            wishlist_dict['wishlist_torrents'][wishlist_index]['id'])
                    elif user_input == 3:
                        exit()
                    else:
                        console.print("Invalid Input.", style="red")
                except ValueError:
                    console.print("Invlid input", style="red")
                except KeyboardInterrupt:
                    console.print("Exiting...", style="red")
                    exit()
        else:
            console.print("Wishlist is empty. Exiting...", style="magenta")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        console.print("\nExiting...", style="red")
        exit()
    exit()
Example #8
0
def render(panel, width=50) -> str:
    console = Console(file=io.StringIO(), width=50, legacy_windows=False)
    console.print(panel)
    return console.file.getvalue()
Example #9
0
def results(result: dict, verbose: bool) -> None:
    """
    Print out the preview result to the console using rich tables.

    Args:
        result: A dictionary of slot configurations including occupancy values
            for the requested job size.
        verbose: A value to extend the generated output.
    """
    console = Console()
    table = Table(show_header=True, header_style="bold cyan")

    if verbose:
        table.add_column("Node", style="dim", width=12)

    table.add_column("Slot Type")
    table.add_column("Job fits", justify="right")

    if verbose:
        table.add_column("Slot usage", justify="right")
        table.add_column("RAM usage", justify="center")
        table.add_column("GPU usage", justify="center")

    table.add_column("Amount of similar jobs", justify="right")
    table.add_column("Wall Time on IDLE", justify="right")

    for slot in result['preview']:
        if slot['fits'] == "YES":
            color = 'green'
            if verbose:
                table.add_row(
                    f"[{color}]{slot['name']}[/{color}]",
                    f"[{color}]{slot['type']}[/{color}]",
                    f"[{color}]{slot['fits']}[/{color}]",
                    f"[{color}]{slot['core_usage']} Cores[/{color}]",
                    f"[{color}]{slot['ram_usage']}[/{color}]",
                    f"[{color}]{slot['gpu_usage']}[/{color}]",
                    f"[{color}]{slot['sim_jobs']}[/{color}]",
                    f"[{color}]{slot['wall_time_on_idle']} min[/{color}]")
            else:
                table.add_row(
                    f"[{color}]{slot['type']}[/{color}]",
                    f"[{color}]{slot['fits']}[/{color}]",
                    f"[{color}]{slot['sim_jobs']}[/{color}]",
                    f"[{color}]{slot['wall_time_on_idle']} min[/{color}]")
        else:
            color = 'red'
            if verbose:
                table.add_row(
                    f"[{color}]{slot['name']}[/{color}]",
                    f"[{color}]{slot['type']}[/{color}]",
                    f"[{color}]{slot['fits']}[/{color}]",
                    f"[{color}]{slot['core_usage']} Cores[/{color}]",
                    f"[{color}]{slot['ram_usage']}[/{color}]",
                    f"[{color}]{slot['gpu_usage']}[/{color}]",
                    f"[{color}]{slot['sim_jobs']}[/{color}]",
                    f"[{color}]{slot['wall_time_on_idle']} min[/{color}]")
            else:
                table.add_row(
                    f"[{color}]{slot['type']}[/{color}]",
                    f"[{color}]{slot['fits']}[/{color}]",
                    f"[{color}]{slot['sim_jobs']}[/{color}]",
                    f"[{color}]{slot['wall_time_on_idle']} min[/{color}]")

    console.print("---------------------- PREVIEW ----------------------")
    console.print(table)
Example #10
0
def report(analysis):
    benchmarks = format_benchmarks(analysis)
    results = format_results(analysis)
    conclusion = format_conclusion(analysis)

    console = Console()

    title = "Paired T-test analysis for Gradle Profiler Benchmarks"
    console.print(f"\n🔥 [bold cyan]{title}[/bold cyan]\n")
    console.print(
        f"[bold magenta]- Baseline[/bold magenta] → {analysis.baseline.benchmark_file}"
    )
    console.print(
        f"[bold magenta]- Modified[/bold magenta] → {analysis.modified.benchmark_file}"
    )

    details = "Details for benchmarks"
    console.print(f"\n🔥 [bold cyan]{details}[/bold cyan]\n")
    console.print(benchmarks)

    outcomes = "Outcomes from hyphotesis testing (h0 versus h1, left-tailed)"
    console.print(f"\n🔥 [bold cyan]{outcomes}[/bold cyan]\n")
    console.print(results)

    console.print("\n🔥 [bold cyan]Conclusions[/bold cyan]")
    console.print(conclusion)
Example #11
0
def view_anndata_setup(source: Union[anndata.AnnData, dict, str]):
    """
    Prints setup anndata.

    Parameters
    ----------
    source
        Either AnnData, path to saved AnnData, path to folder with adata.h5ad,
        or scvi-setup-dict (adata.uns['_scvi'])

    Examples
    --------
    >>> scvi.data.view_anndata_setup(adata)
    >>> scvi.data.view_anndata_setup('saved_model_folder/adata.h5ad')
    >>> scvi.data.view_anndata_setup('saved_model_folder/')
    >>> scvi.data.view_anndata_setup(adata.uns['_scvi'])
    """
    if isinstance(source, anndata.AnnData):
        adata = source
    elif isinstance(source, str):
        # check if user passed in folder or anndata
        if source.endswith("h5ad"):
            path = source
            adata = anndata.read(path)
        else:
            path = os.path.join(source, "adata.h5ad")
            if os.path.exists(path):
                adata = anndata.read(path)
            else:
                path = os.path.join(source, "attr.pkl")
                with open(path, "rb") as handle:
                    adata = None
                    setup_dict = pickle.load(handle)["scvi_setup_dict_"]
    elif isinstance(source, dict):
        adata = None
        setup_dict = source
    else:
        raise ValueError(
            "Invalid source passed in. Must be either AnnData, path to saved AnnData, "
            +
            "path to folder with adata.h5ad or scvi-setup-dict (adata.uns['_scvi'])"
        )

    if adata is not None:
        if "_scvi" not in adata.uns.keys():
            raise ValueError("Please run setup_anndata() on your adata first.")
        setup_dict = adata.uns["_scvi"]

    summary_stats = setup_dict["summary_stats"]
    data_registry = setup_dict["data_registry"]
    mappings = setup_dict["categorical_mappings"]
    version = setup_dict["scvi_version"]

    rich.print("Anndata setup with scvi-tools version {}.".format(version))

    n_cat = 0
    n_covs = 0
    if "extra_categorical_mappings" in setup_dict.keys():
        n_cat = len(setup_dict["extra_categoricals"]["mappings"])
    if "extra_continuous_keys" in setup_dict.keys():
        n_covs = len(setup_dict["extra_continuous_keys"])

    in_colab = "google.colab" in sys.modules
    force_jupyter = None if not in_colab else True
    console = Console(force_jupyter=force_jupyter)
    t = rich.table.Table(title="Data Summary")
    t.add_column("Data",
                 justify="center",
                 style="dodger_blue1",
                 no_wrap=True,
                 overflow="fold")
    t.add_column("Count",
                 justify="center",
                 style="dark_violet",
                 no_wrap=True,
                 overflow="fold")
    data_summary = {
        "Cells": summary_stats["n_cells"],
        "Vars": summary_stats["n_vars"],
        "Labels": summary_stats["n_labels"],
        "Batches": summary_stats["n_batch"],
        "Proteins": summary_stats["n_proteins"],
        "Extra Categorical Covariates": n_cat,
        "Extra Continuous Covariates": n_covs,
    }
    for data, count in data_summary.items():
        t.add_row(data, str(count))
    console.print(t)

    t = rich.table.Table(title="SCVI Data Registry")
    t.add_column("Data",
                 justify="center",
                 style="dodger_blue1",
                 no_wrap=True,
                 overflow="fold")
    t.add_column(
        "scvi-tools Location",
        justify="center",
        style="dark_violet",
        no_wrap=True,
        overflow="fold",
    )

    for scvi_data_key, data_loc in data_registry.items():
        attr_name = data_loc["attr_name"]
        attr_key = data_loc["attr_key"]
        if attr_key == "None":
            scvi_data_str = "adata.{}".format(attr_name)
        else:
            scvi_data_str = "adata.{}['{}']".format(attr_name, attr_key)

        t.add_row(scvi_data_key, scvi_data_str)

    console.print(t)

    t = _categorical_mappings_table("Label Categories", "_scvi_labels",
                                    mappings)
    console.print(t)
    t = _categorical_mappings_table("Batch Categories", "_scvi_batch",
                                    mappings)
    console.print(t)

    if "extra_categoricals" in setup_dict.keys():
        t = _extra_categoricals_table(setup_dict)
        console.print(t)

    if "extra_continuous_keys" in setup_dict.keys():
        t = _extra_continuous_table(adata, setup_dict)
        console.print(t)
        ['老年', '是', '否', '好'],
        ['老年', '是', '否', '非常好'],
        ['老年', '否', '否', '一般'],
    ])
    Y = np.array([
        '否', '否', '是', '是', '否', '否', '否', '是', '是', '是', '是', '是', '是', '是',
        '否'
    ])
    cart.fit(X, Y)

    # show in table
    pred = cart.predict(X)
    table = Table('x', 'y', 'pred')
    for x, y, y_hat in zip(X, Y, pred):
        table.add_row(*map(str, [x, y, y_hat]))
    console.print(table)

    # -------------------------- Example 2 ----------------------------------------
    # but unpruned decision tree doesn't generalize well for test data
    print("Example 2:")
    X = np.array([
        ['青年', '否', '否', '一般'],
        ['青年', '否', '否', '好'],
        ['青年', '是', '是', '一般'],
        ['青年', '否', '否', '一般'],
        ['老年', '否', '否', '一般'],
        ['老年', '否', '否', '好'],
        ['老年', '是', '是', '好'],
        ['老年', '否', '是', '非常好'],
        ['老年', '否', '是', '非常好'],
        ['老年', '否', '是', '非常好'],
Example #13
0
def main():
    colorama.init(autoreset=True)
    c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
    c2 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
    c3 = colorama.Fore.RED + colorama.Back.LIGHTGREEN_EX
    c4 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
    c5 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
    c6 = colorama.Fore.RED + colorama.Back.LIGHTCYAN_EX
    c7 = colorama.Fore.BLACK + colorama.Back.MAGENTA
    cr = colorama.Style.RESET_ALL
    new_lang = None
    overwrite = False
    copy = False
    print_only = False
    help_me = False
    invalid_cmd = None
    line_numbers = False

    expected_arg = ("A SeleniumBase Python file")
    command_args = sys.argv[2:]
    seleniumbase_file = command_args[0]
    if not seleniumbase_file.endswith('.py'):
        seleniumbase_file = (c7 + ">>" + c5 + " " + seleniumbase_file + " " +
                             c7 + "<<" + cr)
        bad_file_error = ("\n`%s` is not a Python file!\n\n"
                          "Expecting: [%s]" %
                          (seleniumbase_file, expected_arg))
        bad_file_error = bad_file_error.replace(
            "is not a Python file!", c3 + "is not a Python file!" + cr)
        bad_file_error = bad_file_error.replace(expected_arg,
                                                c4 + expected_arg + cr)
        bad_file_error = bad_file_error.replace("Expecting:",
                                                c3 + "Expecting:" + cr)
        print(bad_file_error)
        help_me = True

    if len(command_args) >= 2 and not help_me:
        options = command_args[1:]
        for option in options:
            option = option.lower()
            if option == "help" or option == "--help":
                help_me = True
            elif option == "-o" or option == "--overwrite":
                overwrite = True
            elif option == "-c" or option == "--copy":
                copy = True
            elif option == "-p" or option == "--print":
                print_only = True
            elif option == "-n":
                line_numbers = True
            elif option == "--en" or option == "--english":
                new_lang = "English"
            elif option == "--zh" or option == "--chinese":
                new_lang = "Chinese"
            elif option == "--nl" or option == "--dutch":
                new_lang = "Dutch"
            elif option == "--fr" or option == "--french":
                new_lang = "French"
            elif option == "--it" or option == "--italian":
                new_lang = "Italian"
            elif option == "--ja" or option == "--japanese":
                new_lang = "Japanese"
            elif option == "--ko" or option == "--korean":
                new_lang = "Korean"
            elif option == "--pt" or option == "--portuguese":
                new_lang = "Portuguese"
            elif option == "--ru" or option == "--russian":
                new_lang = "Russian"
            elif option == "--es" or option == "--spanish":
                new_lang = "Spanish"
            else:
                invalid_cmd = "\n===> INVALID OPTION: >> %s <<\n" % option
                invalid_cmd = invalid_cmd.replace('>> ', ">>" + c5 + " ")
                invalid_cmd = invalid_cmd.replace(' <<', " " + cr + "<<")
                invalid_cmd = invalid_cmd.replace('>>', c7 + ">>" + cr)
                invalid_cmd = invalid_cmd.replace('<<', c7 + "<<" + cr)
                help_me = True
                break
    else:
        help_me = True

    specify_lang = ("\n>* You must specify a language to translate to! *<\n"
                    "\n"
                    ">    ********  Language Options:  ********    <\n"
                    "   --en / --English    |    --zh / --Chinese\n"
                    "   --nl / --Dutch      |    --fr / --French\n"
                    "   --it / --Italian    |    --ja / --Japanese\n"
                    "   --ko / --Korean     |    --pt / --Portuguese\n"
                    "   --ru / --Russian    |    --es / --Spanish\n")
    specify_action = ("\n>* You must specify an action type! *<\n"
                      "\n"
                      "> *** Action Options: *** <\n"
                      "      -p / --print\n"
                      "      -o / --overwrite\n"
                      "      -c / --copy\n")
    example_run = (
        "\n> *** Examples: *** <\n"
        "Translate test_1.py into Chinese and only print the output:\n"
        " >$ sbase translate test_1.py --zh -p\n"
        "Translate test_2.py into Portuguese and overwrite the file:\n"
        " >$ sbase translate test_2.py --pt -o\n"
        "Translate test_3.py into Dutch and make a copy of the file:\n"
        " >$ sbase translate test_3.py --nl -c\n")
    usage = ("\n> *** Usage: *** <\n"
             " >$ sbase translate [SB_FILE.py] [LANGUAGE] [ACTION]\n")
    specify_lang = specify_lang.replace('>*', c5 + ">*")
    specify_lang = specify_lang.replace('*<', "*<" + cr)
    specify_lang = specify_lang.replace("Language Options:",
                                        c4 + "Language Options:" + cr)
    specify_lang = specify_lang.replace(">    ********  ",
                                        c3 + ">    ********  " + cr)
    specify_lang = specify_lang.replace("  ********    <",
                                        c3 + "  ********    <" + cr)
    specify_lang = specify_lang.replace("--en", c2 + "--en" + cr)
    specify_lang = specify_lang.replace("--zh", c2 + "--zh" + cr)
    specify_lang = specify_lang.replace("--nl", c2 + "--nl" + cr)
    specify_lang = specify_lang.replace("--fr", c2 + "--fr" + cr)
    specify_lang = specify_lang.replace("--it", c2 + "--it" + cr)
    specify_lang = specify_lang.replace("--ja", c2 + "--ja" + cr)
    specify_lang = specify_lang.replace("--ko", c2 + "--ko" + cr)
    specify_lang = specify_lang.replace("--pt", c2 + "--pt" + cr)
    specify_lang = specify_lang.replace("--ru", c2 + "--ru" + cr)
    specify_lang = specify_lang.replace("--es", c2 + "--es" + cr)
    specify_lang = specify_lang.replace("--English", c2 + "--English" + cr)
    specify_lang = specify_lang.replace("--Chinese", c2 + "--Chinese" + cr)
    specify_lang = specify_lang.replace("--Dutch", c2 + "--Dutch" + cr)
    specify_lang = specify_lang.replace("--French", c2 + "--French" + cr)
    specify_lang = specify_lang.replace("--Italian", c2 + "--Italian" + cr)
    specify_lang = specify_lang.replace("--Japanese", c2 + "--Japanese" + cr)
    specify_lang = specify_lang.replace("--Korean", c2 + "--Korean" + cr)
    specify_lang = specify_lang.replace("--Portuguese",
                                        c2 + "--Portuguese" + cr)
    specify_lang = specify_lang.replace("--Russian", c2 + "--Russian" + cr)
    specify_lang = specify_lang.replace("--Spanish", c2 + "--Spanish" + cr)
    specify_action = specify_action.replace(">*", c6 + ">*")
    specify_action = specify_action.replace("*<", "*<" + cr)
    specify_action = specify_action.replace("Action Options:",
                                            c4 + "Action Options:" + cr)
    specify_action = specify_action.replace("> *** ", c3 + "> *** " + cr)
    specify_action = specify_action.replace(" *** <", c3 + " *** <" + cr)
    specify_action = specify_action.replace(" -p", " " + c1 + "-p" + cr)
    specify_action = specify_action.replace(" -o", " " + c1 + "-o" + cr)
    specify_action = specify_action.replace(" -c", " " + c1 + "-c" + cr)
    specify_action = specify_action.replace(" --print",
                                            " " + c1 + "--print" + cr)
    specify_action = specify_action.replace(" --overwrite",
                                            " " + c1 + "--overwrite" + cr)
    specify_action = specify_action.replace(" --copy",
                                            " " + c1 + "--copy" + cr)
    example_run = example_run.replace("Examples:", c4 + "Examples:" + cr)
    example_run = example_run.replace("> *** ", c3 + "> *** " + cr)
    example_run = example_run.replace(" *** <", c3 + " *** <" + cr)
    example_run = example_run.replace(" -p", " " + c1 + "-p" + cr)
    example_run = example_run.replace(" -o", " " + c1 + "-o" + cr)
    example_run = example_run.replace(" -c", " " + c1 + "-c" + cr)
    example_run = example_run.replace("Chinese", c2 + "Chinese" + cr)
    example_run = example_run.replace("Portuguese", c2 + "Portuguese" + cr)
    example_run = example_run.replace("Dutch", c2 + "Dutch" + cr)
    example_run = example_run.replace(" --zh", " " + c2 + "--zh" + cr)
    example_run = example_run.replace(" --pt", " " + c2 + "--pt" + cr)
    example_run = example_run.replace(" --nl", " " + c2 + "--nl" + cr)
    example_run = example_run.replace("sbase", c4 + "sbase" + cr)
    usage = usage.replace("Usage:", c4 + "Usage:" + cr)
    usage = usage.replace("> *** ", c3 + "> *** " + cr)
    usage = usage.replace(" *** <", c3 + " *** <" + cr)
    usage = usage.replace("SB_FILE.py", c4 + "SB_FILE.py" + cr)
    usage = usage.replace("LANGUAGE", c2 + "LANGUAGE" + cr)
    usage = usage.replace("ACTION", c1 + "ACTION" + cr)

    if help_me:
        message = ""
        if invalid_cmd:
            message += invalid_cmd
        message += (specify_lang + specify_action + example_run + usage)
        print("")
        raise Exception(message)
    if not overwrite and not copy and not print_only:
        message = specify_action + example_run + usage
        if not new_lang:
            message = specify_lang + specify_action + example_run + usage
        print("")
        raise Exception(message)
    if not new_lang:
        print("")
        raise Exception(specify_lang + example_run + usage)
    if overwrite and copy:
        part_1 = ('\n* You can choose either {-o / --overwrite} '
                  'OR {-c / --copy}, BUT * NOT BOTH *!\n')
        part_1 = part_1.replace("-o ", c1 + "-o" + cr + " ")
        part_1 = part_1.replace("--overwrite", c1 + "--overwrite" + cr)
        part_1 = part_1.replace("-c ", c1 + "-c" + cr + " ")
        part_1 = part_1.replace("--copy", c1 + "--copy" + cr)
        part_1 = part_1.replace("* NOT BOTH *", c6 + "* NOT BOTH *" + cr)
        message = part_1 + example_run + usage
        print("")
        raise Exception(message)

    with open(seleniumbase_file, 'r', encoding='utf-8') as f:
        all_code = f.read()
    if "def test_" not in all_code and "from seleniumbase" not in all_code:
        print("")
        raise Exception("\n\n`%s` is not a valid SeleniumBase test file!\n"
                        "\nExpecting: [%s]\n" %
                        (seleniumbase_file, expected_arg))
    all_code = all_code.replace("\t", "    ")
    code_lines = all_code.split('\n')

    seleniumbase_lines, changed, d_l = process_test_file(code_lines, new_lang)
    detected_lang = d_l

    if not changed:
        msg = ('\n*> [%s] was already in %s! * No changes were made! <*\n'
               '' % (seleniumbase_file, new_lang))
        msg = msg.replace("*> ", "*> " + c2).replace(" <*", cr + " <*")
        print(msg)
        return

    save_line = ("[[[[%s]]]] was translated to [[[%s]]]! "
                 "(Previous: %s)\n"
                 "" % (seleniumbase_file, new_lang, detected_lang))
    save_line = save_line.replace("[[[[", "" + c4)
    save_line = save_line.replace("]]]]", cr + "")
    save_line = save_line.replace("[[[", "" + c2)
    save_line = save_line.replace("]]]", cr + "")

    if print_only:
        console_width = None  # width of console output when running script
        used_width = None  # code_width and few spaces on right for padding
        magic_console = None
        magic_syntax = None
        try:
            console_width = os.popen('stty size', 'r').read().split()[1]
            if console_width:
                console_width = int(console_width)
        except Exception:
            console_width = None

        if sys.version_info[0] == 3 and sys.version_info[1] >= 6:
            from rich.console import Console
            from rich.syntax import Syntax
            python_code = "\n".join(seleniumbase_lines)
            code_width = 1

            w = 0  # line number whitespace
            if line_numbers:
                w = 4
                num_lines = len(code_lines)
                if num_lines >= 10:
                    w = 5
                if num_lines >= 100:
                    w = 6
                if num_lines >= 1000:
                    w = 7

            new_sb_lines = []
            for line in seleniumbase_lines:
                if line.endswith("  # noqa") and line.count("  # noqa") == 1:
                    line = line.replace("  # noqa", "")
                line_length2 = len(line)  # Normal Python string length used
                line_length = get_width(line)  # Special characters count 2X
                if line_length > code_width:
                    code_width = line_length

                if console_width:
                    # If line is larger than console_width, try to optimize it.
                    # Smart Python word wrap to be used with valid indentation.
                    if line_length + w > console_width:  # 5 is line number ws
                        if line.count('  # ') == 1:  # Has comments like this
                            if get_width(line.split('  # ')
                                         [0]) + w <= console_width:
                                new_sb_lines.append(line)
                                continue
                        elif line.count(' # ') == 1:  # Has bad flake8 comment
                            if get_width(
                                    line.split(' # ')[0]) + w <= console_width:
                                new_sb_lines.append(line)
                                continue
                        if line.startswith("from") and " import " in line:
                            line1 = line.split(" import ")[0] + " \\"
                            line2 = "    import " + line.split(" import ")[1]
                            new_sb_lines.append(line1)
                            new_sb_lines.append(line2)
                            continue
                        elif line.count('(') == 1 and line.count(')') == 1:
                            whitespace = line_length2 - len(line.lstrip())
                            new_ws = line[0:whitespace] + "    "
                            line1 = line.split('(')[0] + '('
                            line2 = new_ws + line.split('(')[1]
                            if not ('):') in line2:
                                new_sb_lines.append(line1)
                                if get_width(line2) + w > console_width:
                                    if line2.count('", "') == 1:
                                        line2a = line2.split('", "')[0] + '",'
                                        line2b = new_ws + '"' + (
                                            line2.split('", "')[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                    elif line2.count("', '") == 1:
                                        line2a = line2.split("', '")[0] + "',"
                                        line2b = new_ws + "'" + (
                                            line2.split("', '")[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                    elif line2.count("://") == 1 and (
                                            line2.count('")') == 1):
                                        line2a = line2.split("://")[0] + '://"'
                                        line2b = new_ws + '"' + (
                                            line2.split("://")[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                    elif line2.count("://") == 1 and (
                                            line2.count("')") == 1):
                                        line2a = line2.split("://")[0] + "://'"
                                        line2b = new_ws + "'" + (
                                            line2.split("://")[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                    elif line2.count('="') == 1 and (
                                            line2.lstrip().startswith("'")):
                                        line2a = line2.split('="')[0] + "='"
                                        line2b = new_ws + "'\"" + (
                                            line2.split('="')[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                    elif line2.count("='") == 1 and (
                                            line2.lstrip().startswith('"')):
                                        line2a = line2.split("='")[0] + '="'
                                        line2b = new_ws + '"\'' + (
                                            line2.split("='")[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                new_sb_lines.append(line2)
                            elif get_width(line2) + 4 + w <= console_width:
                                line2 = "    " + line2
                                new_sb_lines.append(line1)
                                new_sb_lines.append(line2)
                            else:
                                new_sb_lines.append(line)
                            continue
                        elif line.count('("') == 1:
                            whitespace = line_length2 - len(line.lstrip())
                            new_ws = line[0:whitespace] + "    "
                            line1 = line.split('("')[0] + '('
                            line2 = new_ws + '"' + line.split('("')[1]
                            if not ('):') in line2:
                                new_sb_lines.append(line1)
                                if get_width(line2) + w > console_width:
                                    if line2.count('" in self.') == 1:
                                        line2a = line2.split(
                                            '" in self.')[0] + '" in'
                                        line2b = new_ws + "self." + (
                                            line2.split('" in self.')[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                new_sb_lines.append(line2)
                            elif get_width(line2) + 4 + w <= console_width:
                                line2 = "    " + line2
                                new_sb_lines.append(line1)
                                new_sb_lines.append(line2)
                            else:
                                new_sb_lines.append(line)
                            continue
                        elif line.count("('") == 1:
                            whitespace = line_length2 - len(line.lstrip())
                            new_ws = line[0:whitespace] + "    "
                            line1 = line.split("('")[0] + '('
                            line2 = new_ws + "'" + line.split("('")[1]
                            if not ('):') in line2:
                                new_sb_lines.append(line1)
                                if get_width(line2) + w > console_width:
                                    if line2.count("' in self.") == 1:
                                        line2a = line2.split(
                                            "' in self.")[0] + "' in"
                                        line2b = new_ws + "self." + (
                                            line2.split("' in self.")[1])
                                        new_sb_lines.append(line2a)
                                        new_sb_lines.append(line2b)
                                        continue
                                new_sb_lines.append(line2)
                            elif get_width(line2) + 4 + w <= console_width:
                                line2 = "    " + line2
                                new_sb_lines.append(line1)
                                new_sb_lines.append(line2)
                            else:
                                new_sb_lines.append(line)
                            continue
                        elif line.count('= "') == 1 and line.count('://') == 1:
                            whitespace = line_length2 - len(line.lstrip())
                            new_ws = line[0:whitespace] + "    "
                            line1 = line.split('://')[0] + '://" \\'
                            line2 = new_ws + '"' + line.split('://')[1]
                            new_sb_lines.append(line1)
                            if get_width(line2) + w > console_width:
                                if line2.count('/') > 0:
                                    slash_one = line2.find('/')
                                    line2a = line2[:slash_one + 1] + '" \\'
                                    line2b = new_ws + '"' + line2[slash_one +
                                                                  1:]
                                    new_sb_lines.append(line2a)
                                    new_sb_lines.append(line2b)
                                    continue
                            new_sb_lines.append(line2)
                            continue
                        elif line.count("= '") == 1 and line.count('://') == 1:
                            whitespace = line_length2 - len(line.lstrip())
                            new_ws = line[0:whitespace] + "    "
                            line1 = line.split('://')[0] + '://" \\'
                            line2 = new_ws + "'" + line.split('://')[1]
                            new_sb_lines.append(line1)
                            if get_width(line2) + w > console_width:
                                if line2.count('/') > 0:
                                    slash_one = line2.find('/')
                                    line2a = line2[:slash_one + 1] + "' \\"
                                    line2b = new_ws + "'" + line2[slash_one +
                                                                  1:]
                                    new_sb_lines.append(line2a)
                                    new_sb_lines.append(line2b)
                                    continue
                            new_sb_lines.append(line2)
                            continue
                    new_sb_lines.append(line)

            if new_sb_lines:
                seleniumbase_lines = new_sb_lines
                python_code = "\n".join(seleniumbase_lines)

            extra_r_spaces = 2
            if console_width and (code_width + extra_r_spaces < console_width):
                used_width = code_width + extra_r_spaces

            magic_syntax = Syntax(python_code,
                                  "python",
                                  theme="monokai",
                                  line_numbers=line_numbers,
                                  code_width=used_width,
                                  word_wrap=False)
            magic_console = Console()
        print("")
        print(save_line)
        print(c1 + "* Here are the results: >>>" + cr)
        # ----------------------------------------
        dash_length = 62  # May change
        if used_width and used_width + w < console_width:
            dash_length = used_width + w
        elif console_width:
            dash_length = console_width
        dashes = "-" * dash_length
        print(dashes)
        print_success = False
        if magic_syntax:
            try:
                magic_console.print(magic_syntax)  # noqa
                print_success = True
            except Exception:
                pass
        if not magic_syntax or not print_success:
            for line in seleniumbase_lines:
                print(line)
        print(dashes)
        # ----------------------------------------

    new_file_name = None
    if copy:
        base_file_name = seleniumbase_file.split('.py')[0]
        new_locale = MD_F.get_locale_code(new_lang)
        new_ext = "_" + new_locale + ".py"
        for locale in MD_F.get_locale_list():
            ext = "_" + locale + ".py"
            if seleniumbase_file.endswith(ext):
                base_file_name = seleniumbase_file.split(ext)[0]
                break
        new_file_name = base_file_name + new_ext
    elif overwrite:
        new_file_name = seleniumbase_file
    else:
        pass  # Print-only run already done

    if not print_only:
        print("")
        print(save_line)
    else:
        pass  # Print-only run already done

    if new_file_name:
        out_file = codecs.open(new_file_name, "w+", encoding='utf-8')
        out_file.writelines("\r\n".join(seleniumbase_lines))
        out_file.close()
        results_saved = ("The translation was saved to: [[[%s]]]\n"
                         "" % new_file_name)
        results_saved = results_saved.replace("[[[", "" + c1)
        results_saved = results_saved.replace("]]]", cr + "")
        print(results_saved)
Example #14
0
                    if pad_right:
                        yield pad_right
                    yield new_line

            elif align == "right":
                # Padding on left
                pad = Segment(" " * excess_space)
                for line in lines:
                    yield pad
                    yield from line
                    yield new_line

        iter_segments = generate_segments()
        if self.style is not None:
            style = console.get_style(self.style)
            iter_segments = Segment.apply_style(iter_segments, style)
        return iter_segments

    def __rich_measure__(self, console: "Console", max_width: int) -> Measurement:
        measurement = Measurement.get(console, self.renderable, max_width)
        return measurement


if __name__ == "__main__":  # pragma: no cover
    from rich.console import Console

    console = Console()

    for align in ["left", "center", "right"]:
        console.print(Align("Hello\nWorld!\nWorld!!!", align))  # type: ignore
Example #15
0
class TUI:
    def __init__(self):
        self.core = Core()
        self.session = PromptSession(reserve_space_for_menu=6, complete_in_thread=True)
        self.headless = False
        self.console = None
        self.table = None
        self.cfSlugs = None
        self.wowiSlugs = None
        self.tipsDatabase = None
        self.completer = None
        self.os = platform.system()
        install()

    def start(self):
        # Check if headless mode was requested
        if len(sys.argv) == 2 and sys.argv[1].lower() == 'headless':
            self.headless = True
        self.setup_console()
        self.print_header()
        # Check if executable is in good location
        if not glob.glob('World*.app') and not glob.glob('Wow*.exe') or \
                not os.path.isdir(Path('Interface/AddOns')) or not os.path.isdir('WTF'):
            self.console.print('[bold red]This executable should be placed in the same directory where Wow.exe, '
                               'WowClassic.exe or World of Warcraft.app is located. Additionally, make sure that '
                               'this WoW installation was started at least once.[/bold red]\n')
            pause(self.headless)
            sys.exit(1)
        # Detect Classic client
        if os.path.basename(os.getcwd()) == '_classic_':
            self.core.clientType = 'wow_classic'
            set_terminal_title(f'CurseBreaker v{__version__} - Classic')
        # Check if client have write access
        try:
            with open('PermissionTest', 'w') as _:
                pass
            os.remove('PermissionTest')
        except IOError:
            self.console.print('[bold red]CurseBreaker doesn\'t have write rights for the current directory.\n'
                               'Try starting it with administrative privileges.[/bold red]\n')
            pause(self.headless)
            sys.exit(1)
        self.auto_update()
        try:
            self.core.init_config()
        except RuntimeError:
            self.console.print('[bold red]The config file is corrupted. Restore the earlier version from backup.'
                               '[/bold red]\n')
            pause(self.headless)
            sys.exit(1)
        self.setup_table()
        # Curse URI Support
        if len(sys.argv) == 2 and 'twitch://' in sys.argv[1]:
            try:
                self.c_install(sys.argv[1].strip())
            except Exception as e:
                self.handle_exception(e)
            timeout(self.headless)
            sys.exit(0)
        if len(sys.argv) == 2 and '.ccip' in sys.argv[1]:
            try:
                path = sys.argv[1].strip()
                self.c_install(self.core.parse_cf_xml(path))
                if os.path.exists(path):
                    os.remove(path)
            except Exception as e:
                self.handle_exception(e)
            timeout(self.headless)
            sys.exit(0)
        # CLI command
        if len(sys.argv) >= 2:
            command = ' '.join(sys.argv[1:]).split(' ', 1)
            if command[0].lower() == 'headless':
                pass
            elif getattr(self, f'c_{command[0].lower()}', False):
                try:
                    getattr(self, f'c_{command[0].lower()}')(command[1].strip() if len(command) > 1 else False)
                except Exception as e:
                    self.handle_exception(e)
                sys.exit(0)
            else:
                self.console.print('Command not found.')
                sys.exit(0)
        # Addons auto update
        if len(self.core.config['Addons']) > 0 and self.core.config['AutoUpdate']:
            if not self.headless:
                self.console.print('Automatic update of all addons will start in 5 seconds.\n'
                                   'Press any button to enter interactive mode.', highlight=False)
            starttime = time.time()
            keypress = None
            while True:
                if self.headless:
                    break
                elif kbhit():
                    keypress = getch()
                    break
                elif time.time() - starttime > 5:
                    break
            if not keypress:
                if not self.headless:
                    self.print_header()
                try:
                    self.motd_parser()
                    self.c_update(None, True)
                    if self.core.backup_check():
                        self.setup_table()
                        self.console.print(f'\n[green]Backing up WTF directory{"!" if self.headless else ":"}[/green]')
                        self.core.backup_wtf(None if self.headless else self.console)
                    if self.core.config['WAUsername'] != 'DISABLED':
                        self.setup_table()
                        self.c_wago_update(None, False)
                except Exception as e:
                    self.handle_exception(e)
                self.console.print('')
                self.print_log()
                pause(self.headless)
                sys.exit(0)
        if self.headless:
            sys.exit(1)
        self.setup_completer()
        self.print_header()
        self.console.print('Use command [green]help[/green] or press [green]TAB[/green] to see a list of available comm'
                           'ands.\nCommand [green]exit[/green] or pressing [green]CTRL+D[/green] will close the applica'
                           'tion.\n')
        if len(self.core.config['Addons']) == 0:
            self.console.print('Command [green]import[/green] might be used to detect already installed addons.\n')
        # Prompt session
        while True:
            try:
                command = self.session.prompt(HTML('<ansibrightgreen>CB></ansibrightgreen> '), completer=self.completer)
            except KeyboardInterrupt:
                continue
            except EOFError:
                break
            else:
                command = command.split(' ', 1)
                if getattr(self, f'c_{command[0].lower()}', False):
                    try:
                        self.setup_table()
                        getattr(self, f'c_{command[0].lower()}')(command[1].strip() if len(command) > 1 else False)
                        self.setup_completer()
                    except Exception as e:
                        self.handle_exception(e)
                else:
                    self.console.print('Command not found.')

    def auto_update(self):
        if getattr(sys, 'frozen', False) and 'CURSEBREAKER_VARDEXMODE' not in os.environ:
            try:
                if os.path.isfile(sys.executable + '.old'):
                    try:
                        os.remove(sys.executable + '.old')
                    except PermissionError:
                        pass
                payload = requests.get('https://api.github.com/repos/AcidWeb/CurseBreaker/releases/latest',
                                       headers=HEADERS).json()
                if 'name' in payload and 'body' in payload and 'assets' in payload:
                    remoteversion = payload['name']
                    changelog = payload['body']
                    url = None
                    for binary in payload['assets']:
                        if (self.os == 'Windows' and '.exe' in binary['name'])\
                                or (self.os == 'Darwin' and '.zip' in binary['name'])\
                                or (self.os == 'Linux' and '.gz' in binary['name']):
                            url = binary['browser_download_url']
                            break
                    if url and StrictVersion(remoteversion[1:]) > StrictVersion(__version__):
                        self.console.print('[green]Updating CurseBreaker...[/green]')
                        shutil.move(sys.executable, sys.executable + '.old')
                        payload = requests.get(url, headers=HEADERS)
                        if self.os == 'Darwin':
                            zipfile.ZipFile(io.BytesIO(payload.content)).extractall(path=os.path.dirname(
                                os.path.abspath(sys.executable)))
                        else:
                            with open(sys.executable, 'wb') as f:
                                if self.os == 'Windows':
                                    f.write(payload.content)
                                elif self.os == 'Linux':
                                    f.write(gzip.decompress(payload.content))
                        os.chmod(sys.executable, 0o775)
                        self.console.print(f'[bold green]Update complete! The application will be restarted now.'
                                           f'[/bold green]\n\n[green]Changelog:[/green]\n{changelog}\n')
                        self.print_log()
                        pause(self.headless)
                        subprocess.call([sys.executable] + sys.argv[1:])
                        sys.exit(0)
            except Exception as e:
                self.console.print(f'[bold red]Update failed!\n\nReason: {str(e)}[/bold red]\n')
                self.print_log()
                pause(self.headless)
                sys.exit(1)

    def motd_parser(self):
        payload = requests.get('https://storage.googleapis.com/cursebreaker/motd', headers=HEADERS)
        if payload.status_code == 200:
            self.console.print(Panel(payload.content.decode('UTF-8'), title='MOTD', border_style='red'))
            self.console.print('')

    def handle_exception(self, e, table=True):
        if self.table.row_count > 1 and table:
            self.console.print(self.table)
        if getattr(sys, 'frozen', False) and 'CURSEBREAKER_DEBUG' not in os.environ:
            sys.tracebacklimit = 0
            width = 0
        else:
            width = 100
        if isinstance(e, list):
            for es in e:
                self.console.print(Traceback.from_exception(exc_type=es.__class__, exc_value=es,
                                                            traceback=es.__traceback__, width=width))
        else:
            self.console.print(Traceback.from_exception(exc_type=e.__class__, exc_value=e,
                                                        traceback=e.__traceback__, width=width))

    def print_header(self):
        clear()
        if self.headless:
            self.console.print(f'[bold green]CurseBreaker[/bold green] [bold red]v{__version__}[/bold red] | '
                               f'[yellow]{datetime.now()}[/yellow]', highlight=False)
        else:
            self.console.print(Rule(f'[bold green]CurseBreaker[/bold green] [bold red]v{__version__}[/bold red]'))
            self.console.print('')

    def print_log(self):
        if self.headless:
            html = self.console.export_html(inline_styles=True, theme=HEADLESS_TERMINAL_THEME)
            with open('CurseBreaker.html', 'a+', encoding='utf-8') as log:
                log.write(html)

    def setup_console(self):
        if self.headless:
            self.console = Console(record=True)
            if self.os == 'Windows':
                window = windll.kernel32.GetConsoleWindow()
                if window:
                    windll.user32.ShowWindow(window, 0)
        elif 'WINDIR' in os.environ and 'WT_SESSION' not in os.environ and 'ALACRITTY_LOG' not in os.environ:
            set_terminal_size(100, 50)
            windll.kernel32.SetConsoleScreenBufferSize(windll.kernel32.GetStdHandle(-11), wintypes._COORD(100, 200))
            self.console = Console(width=97)
        elif self.os == 'Darwin':
            set_terminal_size(100, 50)
            self.console = Console()
        else:
            self.console = Console()

    def setup_completer(self):
        if not self.cfSlugs or not self.wowiSlugs:
            # noinspection PyBroadException
            try:
                self.cfSlugs = pickle.load(gzip.open(io.BytesIO(
                    requests.get('https://storage.googleapis.com/cursebreaker/cfslugs.pickle.gz',
                                 headers=HEADERS).content)))
                self.wowiSlugs = pickle.load(gzip.open(io.BytesIO(
                    requests.get('https://storage.googleapis.com/cursebreaker/wowislugs.pickle.gz',
                                 headers=HEADERS).content)))
            except Exception:
                self.cfSlugs = []
                self.wowiSlugs = []
        addons = []
        for addon in sorted(self.core.config['Addons'], key=lambda k: k['Name'].lower()):
            addons.append(addon['Name'])
        slugs = ['ElvUI', 'Tukui']
        for item in self.cfSlugs:
            slugs.append(f'cf:{item}')
        for item in self.wowiSlugs:
            slugs.append(f'wowi:{item}')
        slugs.extend(['ElvUI:Dev', 'Shadow&Light:Dev'])
        accounts = []
        for account in self.core.detect_accounts():
            accounts.append(account)
        self.completer = NestedCompleter.from_nested_dict({
            'install': WordCompleter(slugs, ignore_case=True, match_middle=True, WORD=True),
            'uninstall': WordCompleter(addons, ignore_case=True),
            'update': WordCompleter(addons, ignore_case=True),
            'force_update': WordCompleter(addons, ignore_case=True),
            'wago_update': None,
            'status': WordCompleter(addons, ignore_case=True),
            'orphans': None,
            'search': None,
            'recommendations': None,
            'import': {'install': None},
            'export': None,
            'toggle_backup': None,
            'toggle_dev': WordCompleter(addons + ['global'], ignore_case=True, sentence=True),
            'toggle_block': WordCompleter(addons, ignore_case=True, sentence=True),
            'toggle_compact_mode': None,
            'toggle_autoupdate': None,
            'toggle_wago': None,
            'set_wago_api': None,
            'set_wago_wow_account': WordCompleter(accounts, ignore_case=True, sentence=True),
            'uri_integration': None,
            'help': None,
            'exit': None
        })

    def setup_table(self):
        self.table = Table(box=box.SQUARE)
        self.table.add_column('Status', header_style='bold white', no_wrap=True, justify='center')
        self.table.add_column('Name', header_style='bold white')
        self.table.add_column('Version', header_style='bold white')

    def parse_args(self, args):
        parsed = []
        for addon in sorted(self.core.config['Addons'], key=lambda k: len(k['Name']), reverse=True):
            if addon['Name'] in args or addon['URL'] in args:
                parsed.append(addon['Name'])
                args = args.replace(addon['Name'], '', 1)
        return sorted(parsed)

    def parse_link(self, text, link, dev=None):
        if dev == 1:
            dev = ' [B]'
        elif dev == 2:
            dev = ' [A]'
        else:
            dev = ''
        if link:
            obj = Text.from_markup(f'[link={link}]{text}[/link][bold]{dev}[/bold]')
        else:
            obj = Text.from_markup(f'{text}[bold]{dev}[/bold]')
        obj.no_wrap = True
        return obj

    def c_install(self, args, recursion=False):
        if args:
            if args.startswith('-i '):
                args = args[3:]
                optignore = True
            else:
                optignore = False
            dependencies = DependenciesParser(self.core)
            args = re.sub(r'([a-zA-Z0-9_:])([ ]+)([a-zA-Z0-9_:])', r'\1,\3', args)
            addons = [addon.strip() for addon in list(reader([args], skipinitialspace=True))[0]]
            with Progress('{task.completed}/{task.total}', '|', BarColumn(bar_width=None), '|',
                          auto_refresh=False, console=self.console) as progress:
                task = progress.add_task('', total=len(addons))
                while not progress.finished:
                    for addon in addons:
                        installed, name, version, deps = self.core.add_addon(addon, optignore)
                        if installed:
                            self.table.add_row('[green]Installed[/green]', Text(name, no_wrap=True),
                                               Text(version, no_wrap=True))
                            if not recursion:
                                dependencies.add_dependency(deps)
                        else:
                            self.table.add_row('[bold black]Already installed[/bold black]',
                                               Text(name, no_wrap=True), Text(version, no_wrap=True))
                        progress.update(task, advance=1, refresh=True)
            self.console.print(self.table)
            dependencies = dependencies.parse_dependency()
            if dependencies:
                self.setup_table()
                self.c_install(dependencies, recursion=True)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a space-separated list of links as an arg'
                               'ument.[bold white]\n\tFlags:[/bold white]\n\t\t[bold white]-i[/bold white] - Disable th'
                               'e client version check.\n[bold green]Supported URL:[/bold green]\n\thttps://www.cursefo'
                               'rge.com/wow/addons/\[addon_name] [bold white]|[/bold white] cf:\[addon_name]\n\thttps:/'
                               '/www.wowinterface.com/downloads/\[addon_name] [bold white]|[/bold white] wowi:\[addon_i'
                               'd]\n\thttps://www.tukui.org/addons.php?id=\[addon_id] [bold white]|[/bold white] tu:\[a'
                               'ddon_id]\n\thttps://www.tukui.org/classic-addons.php?id=\[addon_id] [bold white]|[/bold'
                               ' white] tuc:\[addon_id]\n\thttps://github.com/\[username]/\[repository_name] [bold whit'
                               'e]|[/bold white] gh:\[username]/\[repository_name]\n\tElvUI [bold white]|[/bold white] '
                               'ElvUI:Dev\n\tTukui\n\tShadow&Light:Dev', highlight=False)

    def c_uninstall(self, args):
        if args:
            if args.startswith('-k '):
                args = args[3:]
                optkeep = True
            else:
                optkeep = False
            addons = self.parse_args(args)
            with Progress('{task.completed}/{task.total}', '|', BarColumn(bar_width=None), '|',
                          auto_refresh=False, console=self.console) as progress:
                task = progress.add_task('', total=len(addons))
                while not progress.finished:
                    for addon in addons:
                        name, version = self.core.del_addon(addon, optkeep)
                        if name:
                            self.table.add_row(f'[bold red]Uninstalled[/bold red]',
                                               Text(name, no_wrap=True), Text(version, no_wrap=True))
                        else:
                            self.table.add_row(f'[bold black]Not installed[/bold black]',
                                               Text(addon, no_wrap=True), Text('', no_wrap=True))
                        progress.update(task, advance=1, refresh=True)
            self.console.print(self.table)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a space-separated list of addon names or '
                               'full links as an argument.\n\t[bold white]Flags:[/bold white]\n\t\t[bold white]-k[/bold'
                               ' white] - Keep the addon files after uninstalling.', highlight=False)

    def c_update(self, args, addline=False, update=True, force=False, provider=False):
        if len(self.core.cfCache) > 0 or len(self.core.wowiCache) > 0:
            self.core.cfCache = {}
            self.core.wowiCache = {}
            self.core.checksumCache = {}
        if args:
            addons = self.parse_args(args)
            compacted = -1
        else:
            addons = sorted(self.core.config['Addons'], key=lambda k: k['Name'].lower())
            compacted = 0
        exceptions = []
        dependencies = DependenciesParser(self.core)
        with Progress('{task.completed:.0f}/{task.total}', '|', BarColumn(bar_width=None), '|',
                      auto_refresh=False, console=None if self.headless else self.console) as progress:
            task = progress.add_task('', total=len(addons))
            if not args:
                self.core.bulk_check(addons)
                self.core.bulk_check_checksum(addons, progress)
            while not progress.finished:
                for addon in addons:
                    try:
                        # noinspection PyTypeChecker
                        name, versionnew, versionold, modified, blocked, source, sourceurl, changelog, deps, dstate = \
                            self.core.update_addon(addon if isinstance(addon, str) else addon['URL'], update, force)
                        dependencies.add_dependency(deps)
                        if provider:
                            source = f' [bold white]{source}[/bold white]'
                        else:
                            source = ''
                        if versionold:
                            if versionold == versionnew:
                                if modified:
                                    self.table.add_row(f'[bold red]Modified[/bold red]{source}',
                                                       self.parse_link(name, sourceurl),
                                                       self.parse_link(versionold, changelog, dstate))
                                else:
                                    if self.core.config['CompactMode'] and compacted > -1:
                                        compacted += 1
                                    else:
                                        self.table.add_row(f'[green]Up-to-date[/green]{source}',
                                                           self.parse_link(name, sourceurl),
                                                           self.parse_link(versionold, changelog, dstate))
                            else:
                                if modified or blocked:
                                    self.table.add_row(f'[bold red]Update suppressed[/bold red]{source}',
                                                       self.parse_link(name, sourceurl),
                                                       self.parse_link(versionold, changelog, dstate))
                                else:
                                    version = self.parse_link(versionnew, changelog, dstate)
                                    version.stylize('yellow')
                                    self.table.add_row(
                                        f'[yellow]{"Updated" if update else "Update available"}[/yellow]{source}',
                                        self.parse_link(name, sourceurl),
                                        version)
                        else:
                            self.table.add_row(f'[bold black]Not installed[/bold black]{source}',
                                               Text(addon, no_wrap=True),
                                               Text('', no_wrap=True))
                    except Exception as e:
                        exceptions.append(e)
                    progress.update(task, advance=1 if args else 0.5, refresh=True)
        if addline:
            self.console.print('')
        self.console.print(self.table)
        dependencies = dependencies.parse_dependency()
        if dependencies and update:
            self.setup_table()
            self.c_install(dependencies, recursion=True)
        if compacted > 0:
            self.console.print(f'Additionally [green]{compacted}[/green] addons are up-to-date.')
        if len(addons) == 0:
            self.console.print('Apparently there are no addons installed by CurseBreaker.\n'
                               'Command [green]import[/green] might be used to detect already installed addons.')
        if len(exceptions) > 0:
            self.handle_exception(exceptions, False)

    def c_force_update(self, args):
        if args:
            self.c_update(args, False, True, True)
        else:
            # noinspection PyTypeChecker
            answer = confirm(HTML('<ansibrightred>Execute a forced update of all addons and overwrite ALL local '
                                  'changes?</ansibrightred>'))
            if answer:
                self.c_update(False, False, True, True)

    def c_status(self, args):
        if args and args.startswith('-s'):
            args = args[2:]
            optsource = True
        else:
            optsource = False
        self.c_update(args, False, False, False, optsource)

    def c_orphans(self, _):
        orphansd, orphansf = self.core.find_orphans()
        self.console.print('[green]Directories that are not part of any installed addon:[/green]')
        for orphan in sorted(orphansd):
            self.console.print(orphan.replace('[GIT]', '[yellow]\[GIT][/yellow]'), highlight=False)
        self.console.print('\n[green]Files that are leftovers after no longer installed addons:[/green]')
        for orphan in sorted(orphansf):
            self.console.print(orphan, highlight=False)

    def c_uri_integration(self, _):
        if self.os == 'Windows':
            self.core.create_reg()
            self.console.print('CurseBreaker.reg file was created. Attempting to import...')
            out = os.system('"' + str(Path(os.path.dirname(sys.executable), 'CurseBreaker.reg')) + '"')
            if out != 0:
                self.console.print('Import failed. Please try to import REG file manually.')
            else:
                os.remove('CurseBreaker.reg')
        else:
            self.console.print('This feature is available only on Windows.')

    def c_toggle_dev(self, args):
        if args:
            status = self.core.dev_toggle(args)
            if status is None:
                self.console.print('[bold red]This addon doesn\'t exist or it is not installed yet.[/bold red]')
            elif status == -1:
                self.console.print('[bold red]This feature can be only used with CurseForge addons.[/bold red]')
            elif status == 0:
                self.console.print('All CurseForge addons are now switched' if args == 'global' else 'Addon switched',
                                   'to the [yellow]beta[/yellow] channel.')
            elif status == 1:
                self.console.print('All CurseForge addons are now switched' if args == 'global' else 'Addon switched',
                                   'to the [red]alpha[/red] channel.')
            elif status == 2:
                self.console.print('All CurseForge addons are now switched' if args == 'global' else 'Addon switched',
                                   'to the [green]stable[/green] channel.')
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts an addon name (or "global") as an'
                               ' argument.', highlight=False)

    def c_toggle_block(self, args):
        if args:
            status = self.core.block_toggle(args)
            if status is None:
                self.console.print('[bold red]This addon does not exist or it is not installed yet.[/bold red]')
            elif status:
                self.console.print('Updates for this addon are now [red]suppressed[/red].')
            else:
                self.console.print('Updates for this addon are [green]no longer suppressed[/green].')
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts an addon name as an argument.')

    def c_toggle_backup(self, _):
        status = self.core.generic_toggle('Backup', 'Enabled')
        self.console.print('Backup of WTF directory is now:',
                           '[green]ENABLED[/green]' if status else '[red]DISABLED[/red]')

    def c_toggle_compact_mode(self, _):
        status = self.core.generic_toggle('CompactMode')
        self.console.print('Table compact mode is now:',
                           '[green]ENABLED[/green]' if status else '[red]DISABLED[/red]')

    def c_toggle_autoupdate(self, _):
        status = self.core.generic_toggle('AutoUpdate')
        self.console.print('The automatic addon update on startup is now:',
                           '[green]ENABLED[/green]' if status else '[red]DISABLED[/red]')

    def c_toggle_wago(self, args):
        if args:
            if args == self.core.config['WAUsername']:
                self.console.print(f'Wago version check is now: [green]ENABLED[/green]\nEntries created by '
                                   f'[bold white]{self.core.config["WAUsername"]}[/bold white] are now included.')
                self.core.config['WAUsername'] = ''
            else:
                self.core.config['WAUsername'] = args.strip()
                self.console.print(f'Wago version check is now: [green]ENABLED[/green]\nEntries created by '
                                   f'[bold white]{self.core.config["WAUsername"]}[/bold white] are now ignored.')
        else:
            if self.core.config['WAUsername'] == 'DISABLED':
                self.core.config['WAUsername'] = ''
                self.console.print('Wago version check is now: [green]ENABLED[/green]')
            else:
                self.core.config['WAUsername'] = '******'
                shutil.rmtree(Path('Interface/AddOns/WeakAurasCompanion'), ignore_errors=True)
                self.console.print('Wago version check is now: [red]DISABLED[/red]')
        self.core.save_config()

    def c_set_wago_api(self, args):
        if args:
            self.console.print('Wago API key is now set.')
            self.core.config['WAAPIKey'] = args.strip()
            self.core.save_config()
        elif self.core.config['WAAPIKey'] != '':
            self.console.print('Wago API key is now removed.')
            self.core.config['WAAPIKey'] = ''
            self.core.save_config()
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts API key as an argument.')

    def c_set_wago_wow_account(self, args):
        if args:
            args = args.strip()
            if os.path.isfile(Path(f'WTF/Account/{args}/SavedVariables/WeakAuras.lua')) or \
                    os.path.isfile(Path(f'WTF/Account/{args}/SavedVariables/Plater.lua')):
                self.console.print(f'WoW account name set to: [bold white]{args}[/bold white]')
                self.core.config['WAAccountName'] = args
                self.core.save_config()
            else:
                self.console.print('Incorrect WoW account name.')
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts the WoW account name as an argument.')

    def c_wago_update(self, _, verbose=True):
        if os.path.isdir(Path('Interface/AddOns/WeakAuras')) or os.path.isdir(Path('Interface/AddOns/Plater')):
            accounts = self.core.detect_accounts()
            if len(accounts) == 0:
                return
            elif len(accounts) > 1 and self.core.config['WAAccountName'] == '':
                if verbose:
                    self.console.print('More than one WoW account detected.\nPlease use [bold white]set_wago_wow_accoun'
                                       't[''/bold white] command to set the correct account name.')
                else:
                    self.console.print('\n[green]More than one WoW account detected.[/green]\nPlease use [bold white]se'
                                       't_wago_wow_account[/bold white] command to set the correct account name.')
                return
            elif len(accounts) == 1 and self.core.config['WAAccountName'] == '':
                self.core.config['WAAccountName'] = accounts[0]
                self.core.save_config()
            wago = WagoUpdater(self.core.config['WAUsername'], self.core.config['WAAccountName'],
                               self.core.config['WAAPIKey'])
            if self.core.wagoCompanionVersion != self.core.config['WACompanionVersion']:
                self.core.config['WACompanionVersion'] = self.core.wagoCompanionVersion
                self.core.save_config()
                force = True
            else:
                force = False
            wago.install_companion(self.core.clientType, force)
            statuswa, statusplater = wago.update()
            if verbose:
                if len(statuswa[0]) > 0 or len(statuswa[1]) > 0:
                    self.console.print('[green]Outdated WeakAuras:[/green]')
                    for aura in statuswa[0]:
                        self.console.print(f'[link={aura[1]}]{aura[0]}[/link]', highlight=False)
                    self.console.print('\n[green]Detected WeakAuras:[/green]')
                    for aura in statuswa[1]:
                        self.console.print(f'[link={aura[1]}]{aura[0]}[/link]', highlight=False)
                if len(statusplater[0]) > 0 or len(statusplater[1]) > 0:
                    if len(statuswa[0]) != 0 or len(statuswa[1]) != 0:
                        self.console.print('')
                    self.console.print('[green]Outdated Plater profiles/scripts:[/green]')
                    for aura in statusplater[0]:
                        self.console.print(f'[link={aura[1]}]{aura[0]}[/link]', highlight=False)
                    self.console.print('\n[green]Detected Plater profiles/scripts:[/green]')
                    for aura in statusplater[1]:
                        self.console.print(f'[link={aura[1]}]{aura[0]}[/link]', highlight=False)
            else:
                if len(statuswa[0]) > 0:
                    self.console.print(f'\n[green]The number of outdated WeakAuras:[/green] '
                                       f'{len(statuswa[0])}', highlight=False)
                if len(statusplater[0]) > 0:
                    self.console.print(f'\n[green]The number of outdated Plater profiles/scripts:[/green] '
                                       f'{len(statusplater[0])}', highlight=False)
        elif verbose:
            self.console.print('No compatible addon is installed.')

    def c_search(self, args):
        if args:
            results = self.core.search(args)
            self.console.print('[green]Top results of your search:[/green]')
            for url in results:
                if self.core.check_if_installed(url):
                    self.console.print(f'[link={url}]{url}[/link] [yellow]\[Installed][/yellow]', highlight=False)
                else:
                    self.console.print(f'[link={url}]{url}[/link]', highlight=False)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a search query as an argument.')

    def c_recommendations(self, _):
        if not self.tipsDatabase:
            # noinspection PyBroadException
            try:
                self.tipsDatabase = pickle.load(gzip.open(io.BytesIO(
                    requests.get('https://storage.googleapis.com/cursebreaker/recommendations.pickle.gz',
                                 headers=HEADERS).content)))
            except Exception:
                self.tipsDatabase = {}
        if len(self.tipsDatabase) > 0:
            found = False
            for tip in self.tipsDatabase:
                breaker = False
                for addon, data in tip['Addons'].items():
                    check = True if self.core.check_if_installed(addon) else False
                    breaker = check == data['Installed']
                if breaker:
                    found = True
                    recomendation = tip["Recomendation"].replace('|n', '\n')
                    self.console.print(f'[bold white underline]{tip["Title"]}[/bold white underline] by [green]'
                                       f'{tip["Author"]}[/green]\n\n{recomendation}\n', highlight=False)
            if not found:
                self.console.print('Not found any recommendations for you. Good job!')

    def c_import(self, args):
        hit, partial_hit, miss = self.core.detect_addons()
        if args == 'install' and len(hit) > 0:
            self.c_install(','.join(hit))
        else:
            self.console.print(f'[green]Addons found:[/green]')
            for addon in hit:
                self.console.print(addon, highlight=False)
            self.console.print(f'\n[yellow]Possible matches:[/yellow]')
            for addon in partial_hit:
                self.console.print(' [bold white]or[/bold white] '.join(addon), highlight=False)
            self.console.print(f'\n[red]Unknown directories:[/red]')
            for addon in miss:
                self.console.print(f'{addon}', highlight=False)
            self.console.print(f'\nExecute [bold white]import install[/bold white] command to install all detected addo'
                               f'ns.\nPossible matches need to be installed manually with the [bold white]install[/bold'
                               f' white] command.\nAddons that are available only on WoWInterface and/or Tukui are not '
                               f'detected by this process.')

    def c_export(self, _):
        payload = self.core.export_addons()
        pyperclip.copy(payload)
        self.console.print(f'{payload}\n\nThe command above was copied to the clipboard.', highlight=False)

    def c_help(self, _):
        self.console.print('[green]install [URL][/green]\n\tCommand accepts a space-separated list of links.\n\t[bold w'
                           'hite]Flags:[/bold white]\n\t\t[bold white]-i[/bold white] - Disable the client version chec'
                           'k.\n'
                           '[green]uninstall [URL/Name][/green]\n\tCommand accepts a space-separated list of addon name'
                           's or full links.\n\t[bold white]Flags:[/bold white]\n\t\t[bold white]-k[/bold white] - Keep'
                           ' the addon files after uninstalling.\n'
                           '[green]update [URL/Name][/green]\n\tCommand accepts a space-separated list of addon names o'
                           'r full links.\n\tIf no argument is provided all non-modified addons will be updated.\n'
                           '[green]force_update [URL/Name][/green]\n\tCommand accepts a space-separated list of addon n'
                           'ames or full links.\n\tSelected addons will be reinstalled or updated regardless of their c'
                           'urrent state.\n\tIf no argument is provided all addons will be forcefully updated.\n'
                           '[green]wago_update[/green]\n\tCommand detects all installed WeakAuras and Plater profiles/s'
                           'cripts.\n\tAnd then generate WeakAuras Companion payload.\n'
                           '[green]status[/green]\n\tPrints the current state of all installed addons.\n\t[bold white]F'
                           'lags:[/bold white]\n\t\t[bold white]-s[/bold white] - Display the source of the addons.\n'
                           '[green]orphans[/green]\n\tPrints list of orphaned directories and files.\n'
                           '[green]search [Keyword][/green]\n\tExecutes addon search on CurseForge.\n'
                           '[green]recommendations[/green]\n\tCheck the list of currently installed addons against a co'
                           'mmunity-driven database of tips.\n'
                           '[green]import[/green]\n\tCommand attempts to import already installed addons.\n'
                           '[green]export[/green]\n\tCommand prints list of all installed addons in a form suitable f'
                           'or sharing.\n'
                           '[green]toggle_backup[/green]\n\tEnables/disables automatic daily backup of WTF directory.\n'
                           '[green]toggle_dev [Name][/green]\n\tCommand accepts an addon name (or "global") as argument'
                           '.\n\tPrioritizes alpha/beta versions for the provided addon.\n'
                           '[green]toggle_block [Name][/green]\n\tCommand accepts an addon name as argument.\n\tBlocks/'
                           'unblocks updating of the provided addon.\n'
                           '[green]toggle_compact_mode [/green]\n\tEnables/disables compact table mode that hides entri'
                           'es of up-to-date addons.\n'
                           '[green]toggle_autoupdate [/green]\n\tEnables/disables the automatic addon update on startup'
                           '.\n'
                           '[green]toggle_wago [Username][/green]\n\tEnables/disables automatic Wago updates.\n\tIf a u'
                           'sername is provided check will start to ignore the specified author.\n'
                           '[green]set_wago_api [API key][/green]\n\tSets Wago API key required to access private entri'
                           'es.\n\tIt can be procured here:'
                           ' [link=https://wago.io/account]https://wago.io/account[/link]\n'
                           '[green]set_wago_wow_account [Account name][/green]\n\tSets WoW account used by Wago updater'
                           '.\n\tNeeded only if compatibile addons are used on more than one WoW account.\n'
                           '[green]uri_integration[/green]\n\tEnables integration with CurseForge page.\n\t[i]"Install"'
                           '[/i] button will now start this application.\n'
                           '\n[bold green]Supported URL:[/bold green]\n\thttps://www.curseforge.com/wow/addons/\[addon_'
                           'name] [bold white]|[/bold white] cf:\[addon_name]\n\thttps://www.wowinterface.com/downloads'
                           '/\[addon_name] [bold white]|[/bold white] wowi:\[addon_id]\n\thttps://www.tukui.org/addons.'
                           'php?id=\[addon_id] [bold white]|[/bold white] tu:\[addon_id]\n\thttps://www.tukui.org/class'
                           'ic-addons.php?id=\[addon_id] [bold white]|[/bold white] tuc:\[addon_id]\n\thttps://github.c'
                           'om/\[username]/\[repository_name] [bold white]|[/bold white] gh:\[username]/\[repository_na'
                           'me]\n\tElvUI [bold white]|[/bold white] ElvUI:Dev\n\tTukui\n\tShadow&Light:Dev',
                           highlight=False)

    def c_exit(self, _):
        sys.exit(0)
def find_mismatched_dashes(plain_output: bool) -> int:
	"""
	Entry point for `se find-mismatched-dashes`
	"""

	parser = argparse.ArgumentParser(description="Find words with mismatched dashes in a set of XHTML files. For example, `extra-physical` in one file and `extraphysical` in another.")
	parser.add_argument("targets", metavar="TARGET", nargs="+", help="an XHTML file, or a directory containing XHTML files")
	args = parser.parse_args()

	console = Console(highlight=False, theme=se.RICH_THEME) # Syntax highlighting will do weird things when printing paths
	return_code = 0
	dashed_words: Dict[str, int] = {} # key: word; value: count
	mismatches: Dict[str, Dict[str, Tuple[int, int]]] = {} # key: base word; value: dict with key: plain word; value: (base count, plain count)
	target_filenames = se.get_target_filenames(args.targets, ".xhtml")
	files_xhtml = []

	# Read files and cache for later
	for filename in target_filenames:
		try:
			with open(filename, "r", encoding="utf-8") as file:
				xhtml = file.read()
				dom = se.easy_xml.EasyXmlTree(xhtml)

				# Save any `alt` and `title` attributes because we may be interested in their contents
				for node in dom.xpath("//*[@alt or @title]"):
					for _, value in node.attrs.items():
						xhtml = xhtml + f" {value} "

				# Strip tags
				xhtml = regex.sub(r"<[^>]+?>", " ", xhtml)

				files_xhtml.append(xhtml)

		except FileNotFoundError:
			se.print_error(f"Couldn’t open file: [path][link=file://{filename}]{filename}[/][/].", plain_output=plain_output)
			return_code = se.InvalidInputException.code

		except se.SeException as ex:
			se.print_error(str(ex) + f" File: [path][link=file://{filename}]{filename}[/][/].", plain_output=plain_output)
			return_code = ex.code

	# Create a list of dashed words
	for xhtml in files_xhtml:
		# This regex excludes words with three dashes like `bric-a-brac`, because removing dashes
		# may erroneously match regular words. Don't match `’` to prevent matches like `life’s-end` -> `s-end`
		for word in regex.findall(r"(?<![\-’])\b\w+\-\w+\b(?![\-’])", xhtml):
			lower_word = word.lower()

			if lower_word in dashed_words:
				dashed_words[lower_word] = dashed_words[lower_word] + 1
			else:
				dashed_words[lower_word] = 1

	# Now iterate over the list and search files for undashed versions of the words
	if dashed_words:
		for xhtml in files_xhtml:
			for dashed_word, count in dashed_words.items():
				plain_word = dashed_word.replace("-", "")

				matches = regex.findall(fr"\b{plain_word}\b", xhtml, flags=regex.IGNORECASE)

				if matches:
					if dashed_word in mismatches:
						if plain_word in mismatches[dashed_word]:
							mismatches[dashed_word][plain_word] = (count, mismatches[dashed_word][plain_word][1] + len(matches))
						else:
							mismatches[dashed_word][plain_word] = (count, len(matches))

					else:
						mismatches[dashed_word] = {}
						mismatches[dashed_word][plain_word] = (count, len(matches))

	# Sort and prepare the output
	lines = []

	for dashed_word, child in mismatches.items():
		for plain_word, counts in child.items():
			lines.append((dashed_word, counts[0], plain_word, counts[1]))

	lines.sort()

	if lines:
		if plain_output:
			for dashed_word, dashed_word_count, plain_word, plain_word_count in lines:
				console.print(f"{dashed_word} ({dashed_word_count})\t{plain_word} ({plain_word_count})")

		else:
			table = Table(show_header=False, show_lines=True, box=box.HORIZONTALS)
			table.add_column("Dashed word")
			table.add_column("Count", style="dim", no_wrap=True)
			table.add_column("Plain word")
			table.add_column("Count", style="dim", no_wrap=True)

			for dashed_word, dashed_word_count, plain_word, plain_word_count in lines:
				table.add_row(f"[link=https://www.merriam-webster.com/dictionary/{urllib.parse.quote(dashed_word)}]{dashed_word}[/]", f"({dashed_word_count})", f"[link=https://www.merriam-webster.com/dictionary/{urllib.parse.quote(plain_word)}]{plain_word}[/]", f"({plain_word_count})")

			console.print(table)

	return return_code
Example #17
0
        dest="soft_wrap",
        default=False,
        help="enable soft wrapping mode",
    )
    parser.add_argument("-t",
                        "--theme",
                        dest="theme",
                        default="monokai",
                        help="pygments theme")
    parser.add_argument(
        "-b",
        "--background-color",
        dest="background_color",
        default=None,
        help="Overide background color",
    )
    args = parser.parse_args()

    from rich.console import Console

    console = Console(force_terminal=args.force_color, width=args.width)

    syntax = Syntax.from_path(
        args.path,
        line_numbers=args.line_numbers,
        word_wrap=args.word_wrap,
        theme=args.theme,
        background_color=args.background_color,
    )
    console.print(syntax, soft_wrap=args.soft_wrap)
Example #18
0
    antwort = console.input(
        auswahl_vorlage.format("Jesua & Elisa", "Adam & Eva", "Lorem & Ipsum"))

    if antwort.lower() == "b":
        console.print(richtig, style="richtig")
        RICHTIGE_ANTWORTEN.append(1)
    else:
        console.print(falsch, style="falsch")
    return None


def frage2():
    console.print("Folgender Prophet wird im Koran am meisten erwähnt:")
    antwort = console.input(
        auswahl_vorlage.format("Mohammad a.s.", "Jesus", "Abraham"))

    if antwort.lower() == "b":
        console.print(richtig, style="richtig")
        RICHTIGE_ANTWORTEN.append(1)
    else:
        console.print(falsch, style="falsch")


if __name__ == '__main__':
    alle_fragen = [frage1, frage2]
    for frage in alle_fragen:
        frage()
    console.print(
        f"Du hast alle Fragen beantwortet und {sum(RICHTIGE_ANTWORTEN)} von {len(alle_fragen)} richtig beantwortet!"
    )
Example #19
0
class Notebook:
    def __init__(self):

        self.EDITOR = os.environ.get('EDITOR', 'nano')
        self.encrypt_key = os.environ.get('NOTE_KEY', None)
        self.today = datetime.datetime.today().strftime("%Y-%m-%d")
        self.reddit_bot = Redditor()
        self.encoding = 'utf-8'
        self.rich_console = Console()

    def create_note(self, title='Untitled', tags='None'):
        with tempfile.NamedTemporaryFile(suffix=".tmp") as tf:
            call([self.EDITOR, tf.name])

            save_flag = input('Do you want to save the note? (y/n): ')
            if not save_flag:
                save_flag = 'y'

            if save_flag == 'y':
                tf.seek(0)
                edited_message = tf.read()

                # handle encryption and string conversion of note
                encrypted_message = self._encrypt_text(edited_message)
                string_message = encrypted_message.decode(self.encoding)

                # handle encryption and string conversion of title
                string_tags = ";".join(tags)
                front_matter = f'{title} | {self.today} | {string_tags}'

                encrypted_front_matter = self._encrypt_text(
                    bytes(front_matter, self.encoding))
                string_front_matter = encrypted_front_matter.decode(
                    self.encoding)

                self.reddit_bot.post_submission(string_front_matter,
                                                string_message)

        return 200

    def list_notes(self):
        notes_metadata = self.reddit_bot.list_submissions()
        table = Table(show_header=True, header_style="bold royal_blue1")
        table.add_column('Date', style="dim")
        table.add_column('Title')
        table.add_column('Tags')
        table.add_column('ID')

        for note in notes_metadata:
            byte_front_matter = self._decrypt_text(
                bytes(note['title'], self.encoding))
            string_front_matter = byte_front_matter.decode(self.encoding)

            title, date, tags = string_front_matter.split(' | ')
            note_link = note['url']
            note_id = note['id']

            hyperlinked_note_id = f'[link={note_link}]{note_id}[/link]'

            table.add_row(date, title, tags, hyperlinked_note_id)

        self.rich_console.print(table)

        return 200

    def get_note(self, id):
        encrypted_note_text = self.reddit_bot.read_submission(id)
        decrypted_note_text = self._decrypt_text(
            bytes(encrypted_note_text, self.encoding))

        note_text = decrypted_note_text.decode(self.encoding)
        markdown_converted = Markdown(note_text)

        self.rich_console.print(markdown_converted)

        return 200

    def _encrypt_text(self, plain_text):
        cipher_suite = Fernet(self.encrypt_key)
        cipher_text = cipher_suite.encrypt(plain_text)

        return cipher_text

    def _decrypt_text(self, cipher_text):
        cipher_suite = Fernet(self.encrypt_key)
        plain_text = cipher_suite.decrypt(cipher_text)

        return plain_text

    def _make_encrypt_key(self):
        key = Fernet.generate_key()
        print(key)

        return key
Example #20
0
while(True):
    choice = ""
    choices = ["1", "2", "3", "help", "exit"]
    while choice not in choices:
        choice = input(">> ").lower().strip()
        if choice not in choices:
            print("[red]Sorry, I didn't catch that. Enter again.[/]")

    if(choice =="1"):
        print("[yellow]\nViewing the README...[/]\n")
        time.sleep(1)
        
        with open("app/README.md") as readme:
            markdown = Markdown(readme.read())
        console.print(markdown)
        print("\n")
        time.sleep(1)
        continue


    if(choice =="2"):
        print("[bold blue]\nGetting Submission Prompt Ready...[/]")
        time.sleep(1)
        
        while(True):
            try:
                webhook_url = console.input("\n[#5499C7]Input a Webhook URL to get Started: [/]")
                if not is_valid_url(webhook_url):
                    raise ValueError("Please provide a valid url, in the form of a protocol (https), hostname (site.com), and arguments (.../example)")  
            except ValueError as e:
Example #21
0
def table_checklist(recon, geo, headinfo, sslinfo, whois, crawl, dns, subd,
                    pscan, dirrec, light, cve, cms, site, virus, owasps, xss,
                    csrf, sqli, cmdi, htmli, report, output, full, trace):

    print('\n\n' + G + '[+]' + Y + ' Confirmation :' + W + '\n')

    ## xu ly 4 truong hop: full, recon, light, owasps
    if full:
        recon = True
        light = True
        owasps = True
    if recon:
        geo = True
        headinfo = True
        sslinfo = True
        whois = True
        crawl = True
        dns = True
        subd = True
        pscan = True
        dirrec = True
    if light:
        cve = True
        cms = True
        site = True
        virus = True
    if owasps:
        xss = True
        csrf = True
        sqli = True
        cmdi = True
        htmli = True
    if report:
        if output == None:
            output = "txt"
        elif output != "txt":
            output = output + " txt"

    console = Console()

    table = Table(show_header=True, header_style="bold magenta")
    table.add_column("Available Modules", style="dim", width=50)
    table.add_column("Selected", justify="", width=12)

    # Recon
    if recon:
        recon_check = "✓ Recon "
    else:
        recon_check = ""
    table.add_row(
        "[red]Reconnaisance[/red]: All Recon Options",
        "[green]" + recon_check + "[/green]",
    )
    if geo:
        geo_check = "✓"
    else:
        geo_check = ""
    table.add_row(
        "\t|- [yellow]GeoIP[/yellow]: Geography IP",
        "[green]" + geo_check + "[/green]",
    )
    if headinfo:
        headinfo_check = "✓"
    else:
        headinfo_check = ""
    table.add_row(
        "\t|- [yellow]Headers[/yellow]: HTTP Header Information",
        "[green]" + headinfo_check + "[/green]",
    )
    if sslinfo:
        sslinfo_check = "✓"
    else:
        sslinfo_check = ""
    table.add_row(
        "\t|- [yellow]SSL Info[/yellow]: SSL Certificate Information",
        "[green]" + sslinfo_check + "[/green]",
    )
    if whois:
        whois_check = "✓"
    else:
        whois_check = ""
    table.add_row(
        "\t|- [yellow]Whois[/yellow]: Quick Whois Lookup",
        "[green]" + whois_check + "[/green]",
    )
    if pscan:
        pscan_check = "✓"
    else:
        pscan_check = ""
    table.add_row(
        "\t|- [yellow]Port Scan[/yellow]: Fast Port Scan",
        "[green]" + pscan_check + "[/green]",
    )
    if dns:
        dns_check = "✓"
    else:
        dns_check = ""
    table.add_row(
        "\t|- [yellow]DNS Enum[/yellow]: DNS Enumeration",
        "[green]" + dns_check + "[/green]",
    )
    if subd:
        subd_check = "✓"
    else:
        subd_check = ""
    table.add_row(
        "\t|- [yellow]Subdom Enum[/yellow]: Sub-Domain Enumeration",
        "[green]" + subd_check + "[/green]",
    )
    if crawl:
        crawl_check = "✓"
    else:
        crawl_check = ""
    table.add_row(
        "\t|- [yellow]Web Crawling[/yellow]: Crawl Target Website",
        "[green]" + crawl_check + "[/green]",
    )
    if dirrec:
        dirrec_check = "✓"
    else:
        dirrec_check = ""
    table.add_row(
        "\t|- [yellow]Dirrec[/yellow]: Directory Traversal",
        "[green]" + dirrec_check + "[/green]",
    )

    # Light
    if light:
        light_check = "✓ Light "
    else:
        light_check = ""
    table.add_row(
        "[red]Light Scan[/red]: All Light Scan Options",
        "[green]" + light_check + "[/green]",
    )
    if cve:
        cve_check = "✓"
    else:
        cve_check = ""
    table.add_row(
        "\t|- [yellow]CVE[/yellow]: Potential Apache CVE",
        "[green]" + cve_check + "[/green]",
    )
    if cms:
        cms_check = "✓"
    else:
        cms_check = ""
    table.add_row(
        "\t|- [yellow]CMS[/yellow]: CMS Detector",
        "[green]" + cms_check + "[/green]",
    )
    if site:
        site_check = "✓"
    else:
        site_check = ""
    table.add_row(
        "\t|- [yellow]Site Vuln[/yellow]: Common Vuln Scanner",
        "[green]" + site_check + "[/green]",
    )
    if virus:
        virus_check = "✓"
    else:
        virus_check = ""
    table.add_row(
        "\t|- [yellow]Virus[/yellow]: Malware URL Scanner",
        "[green]" + virus_check + "[/green]",
    )

    # OWASP
    if owasps:
        owasps_check = "✓ OWASP "
    else:
        owasps_check = ""
    table.add_row(
        "[red]OWASP Scan[/red]: All OWASP Scan Options",
        "[green]" + owasps_check + "[/green]",
    )
    if xss:
        xss_check = "✓"
    else:
        xss_check = ""
    table.add_row(
        "\t|- [yellow]XSS[/yellow]: Cross Site Scripting",
        "[green]" + xss_check + "[/green]",
    )
    if csrf:
        csrf_check = "✓"
    else:
        csrf_check = ""
    table.add_row(
        "\t|- [yellow]CSRF[/yellow]: Cross Site Request Forgery",
        "[green]" + csrf_check + "[/green]",
    )
    if sqli:
        sqli_check = "✓"
    else:
        sqli_check = ""
    table.add_row(
        "\t|- [yellow]SQLi[/yellow]: SQL Injection Scripting",
        "[green]" + sqli_check + "[/green]",
    )
    if cmdi:
        cmdi_check = "✓"
    else:
        cmdi_check = ""
    table.add_row(
        "\t|- [yellow]CMDi[/yellow]: OS Command Injection",
        "[green]" + cmdi_check + "[/green]",
    )
    if htmli:
        htmli_check = "✓"
    else:
        htmli_check = ""
    table.add_row(
        "\t|- [yellow]HTMLi[/yellow]: HTML Injection",
        "[green]" + htmli_check + "[/green]",
    )

    # Report
    table.add_row(
        "[red]Report[/red]: Reporting Options",
        "[green]"
        "[/green]",
    )
    if output != None:
        output_check = "✓ " + output
    table.add_row(
        "\t|- [yellow]Dump[/yellow]: Dumping Retrieved Info",
        "[green]" + output_check + "[/green]",
    )
    if report:
        report_check = "✓ docx"
    else:
        report_check = ""
    table.add_row(
        "\t|- [yellow]Report[/yellow]: Post-scan Docx Reporting",
        "[green]" + report_check + "[/green]",
    )

    # Other
    if trace:
        table.add_row(
            "[red]Others[/red]: Other Options",
            "[green]"
            "[/green]",
        )
        table.add_row(
            "\t|- [yellow]Trace[/yellow]: Trace Route",
            "[green]✓[/green]",
        )
    else:
        pass

    console.print(table)
Example #22
0
def chat_main(client):
    """ (Clubhouse) -> NoneType

    Main function for chat
    """
    max_limit = 20
    channel_speaker_permission = False
    _wait_func = None
    _ping_func = None

    def _request_speaker_permission(client, channel_name, user_id):
        """ (str) -> bool

        Raise hands for permissions
        """
        if not channel_speaker_permission:
            client.audience_reply(channel_name, True, False)
            _wait_func = _wait_speaker_permission(client, channel_name,
                                                  user_id)
            print(
                "[/] You've raised your hand. Wait for the moderator to give you the permission."
            )

    @set_interval(30)
    def _ping_keep_alive(client, channel_name):
        """ (str) -> bool

        Continue to ping alive every 30 seconds.
        """
        client.active_ping(channel_name)
        return True

    @set_interval(10)
    def _wait_speaker_permission(client, channel_name, user_id):
        """ (str) -> bool

        Function that runs when you've requested for a voice permission.
        """
        # Get some random users from the channel.
        _channel_info = client.get_channel(channel_name)
        if _channel_info['success']:
            for _user in _channel_info['users']:
                if _user['user_id'] != user_id:
                    user_id = _user['user_id']
                    break
            # Check if the moderator allowed your request.
            res_inv = client.accept_speaker_invite(channel_name, user_id)
            if res_inv['success']:
                print("[-] Now you have a speaker permission.")
                print(
                    "    Please re-join this channel to activate a permission."
                )
                return False
        return True

    while True:
        # Choose which channel to enter.
        # Join the talk on success.
        user_id = client.HEADERS.get("CH-UserID")
        print_channel_list(client, max_limit)
        channel_name = input("[.] Enter channel_name: ")
        channel_info = client.join_channel(channel_name)
        if not channel_info['success']:
            # Check if this channel_name was taken from the link
            channel_info = client.join_channel(channel_name, "link", "e30=")
            if not channel_info['success']:
                print(
                    f"[-] Error while joining the channel ({channel_info['error_message']})"
                )
                continue

        # List currently available users (TOP 20 only.)
        # Also, check for the current user's speaker permission.
        channel_speaker_permission = False
        console = Console()
        table = Table(show_header=True, header_style="bold magenta")
        table.add_column("user_id", style="cyan", justify="right")
        table.add_column("username")
        table.add_column("name")
        table.add_column("is_speaker")
        table.add_column("is_moderator")
        users = channel_info['users']
        i = 0
        for user in users:
            i += 1
            if i > max_limit:
                break
            table.add_row(
                str(user['user_id']),
                str(user['name']),
                str(user['username']),
                str(user['is_speaker']),
                str(user['is_moderator']),
            )
            # Check if the user is the speaker
            if user['user_id'] == int(user_id):
                channel_speaker_permission = bool(user['is_speaker'])
        console.print(table)

        # Check for the voice level.
        if RTC:
            token = channel_info['token']
            RTC.joinChannel(token, channel_name, "", int(user_id))
        else:
            print("[!] Agora SDK is not installed.")
            print("    You may not speak or listen to the conversation.")

        # Activate pinging
        client.active_ping(channel_name)
        _ping_func = _ping_keep_alive(client, channel_name)
        _wait_func = None

        # Add raise_hands key bindings for speaker permission
        # Sorry for the bad quality
        if not channel_speaker_permission:

            if sys.platform == "darwin":  # OSX
                _hotkey = "9"
            elif sys.platform == "win32":  # Windows
                _hotkey = "ctrl+shift+h"

            print(
                f"[*] Press [{_hotkey}] to raise your hands for the speaker permission."
            )
            keyboard.add_hotkey(_hotkey,
                                _request_speaker_permission,
                                args=(client, channel_name, user_id))

        input("[*] Press [Enter] to quit conversation.\n")
        keyboard.unhook_all()

        # Safely leave the channel upon quitting the channel.
        if _ping_func:
            _ping_func.set()
        if _wait_func:
            _wait_func.set()
        if RTC:
            RTC.leaveChannel()
        client.leave_channel(channel_name)
Example #23
0
                 start_dt: str = None,
                 end_dt: str = None,
                 title: str = None,
                 body: str = None):
        now = pendulum.now()
        self.start_dt = parse_dt_local_tz(start_dt) if start_dt else now
        self.end_dt = parse_dt_local_tz(end_dt) if end_dt else now
        self.created_dt = now
        self.modified_dt = now
        self.title = title if title else self.start_dt.to_day_datetime_string()
        self.body = body
        self.uuid = str(uuid())

    def __repr__(self):
        return f'<Entry uuid: {self.uuid} start_dt: {self.start_dt.to_datetime_string()} body: "{self.body}">'


# NOTE: dev only
if __name__ == "__main__":

    from rich.console import Console

    console = Console()

    t = Timeline()
    t.add_story('2020-02-18', '27th birthday')
    t.add_story()

    console.print(t.stories)
    console.print(t.stories[0].entries)
Example #24
0
import requests, sys

from rich.console import Console

BANNER = '''[magenta]
   __ _          __ _      
  / _(_)_ _ ___ / _| |_  _ 
 |  _| | '_/ -_)  _| | || | [green]A fork of https://github.com/Lexxrt/FireFly[/green]
 |_| |_|_| \___|_| |_|\_, | [green]by https://github.com/dropsql[/green]
                      |__/ 
[/magenta]
'''

console = Console()
console.print(BANNER)

if not __import__('re').match(r'[a-f0-9]{32}', API_KEY):
    console.print(f'[red][-][/red] {API_KEY} isn\'t a numverify.com api key.')
    sys.exit()

if len(sys.argv) == 1:
    console.print(f'py {sys.argv[0]} <number 1> <number 2> (etc.)')
    sys.exit(-1)

for number in sys.argv[1:]:
    console.rule(f'results for number: \'{number}\'')

    r = requests.get(
        url=API_URL.format(key=API_KEY, phone_number=number, format=1))
Example #25
0
def test_print(print_text, result):
    console = Console(record=True)
    console.print(*print_text)
    assert console.export_text(styles=False) == result
Example #26
0
def main(yaml_file, plot, sampler_file, write, direc, label, plot_format):
    """Console script for yabf."""
    if mpi.am_single_or_primary_process:
        console = Console(width=100)
        console.print(
            Panel("Welcome to yabf!", box=box.DOUBLE_EDGE),
            style="bold",
            justify="center",
        )
        start = time.time()

    likelihood = load_likelihood_from_yaml(yaml_file)
    output_prefix = Path(direc) / (label or likelihood.name
                                   or Path(yaml_file).stem)
    if not output_prefix.parent.exists():
        output_prefix.mkdir(parents=True)

    if sampler_file is not None:
        sampler, runkw = load_sampler_from_yaml(
            sampler_file,
            likelihood,
            override={"output_prefix": output_prefix},
        )
    else:
        sampler, runkw = load_from_yaml(
            yaml_file,
            override={"output_prefix": output_prefix},
        )

    # make sure it's the same as the actual sampler.
    output_prefix = sampler.output_file_prefix

    if mpi.am_single_or_primary_process:
        console.print(Rule(f"Sampler [{sampler.__class__.__name__}] "))
        console.print(f"[bold]Sampler Options:[/] {sampler.sampler_kwargs}")
        console.print(f"[bold]Run Options:[/] {runkw}")
        console.print(f"[bold]Output Directory:[/]\t{sampler.output_dir}")
        console.print(f"[bold]Output Prefix:[/]\t{sampler.output_file_prefix}")

        console.print()
        console.print(Rule("Model"))

        console.print("[bold]Likelihoods[/]")
        for lk in likelihood._subcomponents:
            if isinstance(lk, _LikelihoodInterface):
                console.print(lk.name)
        console.print()

        console.print("[bold]Components[/]")
        for loc, cmp in likelihood.child_components.items():
            if not isinstance(cmp, _LikelihoodInterface):
                console.print(loc)
        console.print()

        console.print(
            f"[bold]Active Parameters[/] [blue]({len(likelihood.child_active_params)})[/] "
        )
        _len = max(len(p.name) for p in likelihood.child_active_params)
        _dlen = max(
            len(str(p.determines)) for p in likelihood.child_active_params)
        for p in likelihood.child_active_params:
            det = str(p.determines).replace("'",
                                            "").replace("(",
                                                        "").replace(")", "")
            fid = "[" + str(p.fiducial) + "]"
            console.print(f"{p.name:<{_len}}  {fid:<8} -----> {det:<{_dlen}}")

        fit_params = sum(
            (p.determines for p in likelihood.child_active_params), ())
        console.print()
        console.print("[bold]In-active parameters[/]")
        for lc in likelihood.child_base_parameter_dct:
            if lc not in fit_params:
                console.print(
                    f"{lc} = {utils.get_loc_from_dict(likelihood.fiducial_params, lc)}"
                )

        console.print()
        console.print(Rule("Starting MCMC"))

    mpi.sync_processes()
    mcsamples = sampler.sample(**runkw)
    mpi.sync_processes()

    if mpi.am_single_or_primary_process:
        console.print("Done.\n")
        console.print(Rule())
        console.print()
        console.print(Rule("[bold]Basic Chain Diagnostics[/]"))

        try:
            gr = mcsamples.getGelmanRubin()
        except Exception:
            gr = "unavailable"

        console.print("Gelman-Rubin Statistic: ", gr)
        console.print()
        console.print(Rule("Correlation Lengths"))
        for i, p in enumerate(mcsamples.getParamNames().names):
            corrlength = mcsamples.getCorrelationLength(i, weight_units=False)
            console.print(f"{p.name}:\t{corrlength:1.3e}")

        console.print()
        console.print("Mean (+- std) Posterior Values:")
        mean = mcsamples.getMeans()
        std = mcsamples.getVars()

        for m, s, p in zip(mean, std, mcsamples.getParamNames().names):
            console.print(f"{p.name}:\t{m:1.3e} +- {s:1.3e}")

        if plot and HAVE_MPL:
            g = plots.getSubplotPlotter()
            g.triangle_plot(mcsamples,
                            params=list(likelihood.child_active_params),
                            shaded=True)

            plt.savefig(f"{output_prefix}_corner.{plot_format}")

        if write:
            mcsamples.saveAsText(output_prefix)

        tot = time.time() - start

        console.print(
            f":tada: Finished in {tot//3600}:{(tot%3600)//60}:{(tot%3600)%60} (h:m:s) :tada:",
            style="bold green",
        )
    return 0
Example #27
0
def test_markup_switch():
    """Test markup can be disabled."""
    console = Console(file=StringIO(), markup=False)
    console.print("[bold]foo[/bold]")
    assert console.file.getvalue() == "[bold]foo[/bold]\n"
Example #28
0
def main():
    """Primary workflow"""
    parser = logmuse.add_logging_options(build_argparser())
    args, _ = parser.parse_known_args()
    global _LOGGER
    _LOGGER = logmuse.logger_via_cli(args, make_root=True)
    _LOGGER.debug(f"versions: refgenie {__version__} | refgenconf {rgc_version}")
    _LOGGER.debug(f"Args: {args}")

    if not args.command:
        parser.print_help()
        _LOGGER.error("No command given")
        sys.exit(1)

    if args.command == ALIAS_CMD and not args.subcommand:
        parser.print_help()
        _LOGGER.error("No alias subcommand command given")
        sys.exit(1)

    if (
        args.command == BUILD_CMD
        and args.asset_registry_paths is None
        and not args.reduce
    ):
        parser.error("You must provide an asset-registry-path")
        sys.exit(1)

    gencfg = select_genome_config(
        filename=args.genome_config,
        check_exist=not args.command == INIT_CMD,
        on_missing=lambda fp: fp,
        strict_env=True,
    )
    if gencfg is None and args.command not in [
        GET_REMOTE_ASSET_CMD,
        LIST_REMOTE_CMD,
        POPULATE_REMOTE_CMD,
    ]:
        raise MissingGenomeConfigError(args.genome_config)
    _LOGGER.debug("Determined genome config: {}".format(gencfg))

    skip_read_lock = True if gencfg is None else _skip_lock(args.skip_read_lock, gencfg)
    # From user input we want to construct a list of asset dicts, where each
    # asset has a genome name, asset name, and tag
    if "asset_registry_paths" in args and args.asset_registry_paths:
        _LOGGER.debug("Found registry_path: {}".format(args.asset_registry_paths))
        asset_list = [parse_registry_path(x) for x in args.asset_registry_paths]
        # [{"protocol": 'pname', "genome": 'gname', "asset", 'aname', "seek_key", 'sname', "tag": 'tname'}, ...]
        for a in asset_list:
            # every asset must have a genome, either provided via registry path
            # or the args.genome arg.
            if not a["genome"]:
                if args.genome:
                    a["genome"] = args.genome
                else:
                    _LOGGER.error(
                        "Provided asset registry path ({}/{}:{}) is invalid. See help for usage reference.".format(
                            a["genome"], a["asset"], a["tag"]
                        )
                    )
                    sys.exit(1)
            else:
                if args.genome and args.genome != a["genome"]:
                    _LOGGER.warn(
                        "Two different genomes specified for asset '{}'.".format(
                            a["asset"]
                        )
                    )

    if args.command == INIT_CMD:
        _LOGGER.debug("Initializing refgenie genome configuration")
        entries = OrderedDict(
            {
                CFG_VERSION_KEY: REQ_CFG_VERSION,
                CFG_FOLDER_KEY: os.path.dirname(os.path.abspath(gencfg)),
                CFG_SERVERS_KEY: args.genome_server or [DEFAULT_SERVER],
                CFG_GENOMES_KEY: None,
            }
        )
        if args.settings_json:
            if os.path.isfile(args.settings_json):
                with open(args.settings_json, "r") as json_file:
                    data = json.load(json_file)
                entries.update(data)
            else:
                raise FileNotFoundError(
                    "JSON file with config init settings does not exist: {}".format(
                        args.settings_json
                    )
                )
        if args.genome_folder:
            entries.update({CFG_FOLDER_KEY: args.genome_folder})
        if args.genome_archive_folder:
            entries.update({CFG_ARCHIVE_KEY: args.genome_archive_folder})
        if args.genome_archive_config:
            entries.update({CFG_ARCHIVE_CONFIG_KEY: args.genome_archive_config})
        _LOGGER.debug("initializing with entries: {}".format(entries))
        rgc = RefGenConf(entries=entries, skip_read_lock=skip_read_lock)
        rgc.initialize_config_file(os.path.abspath(gencfg))

    elif args.command == BUILD_CMD:
        if args.reduce:
            refgenie_build_reduce(
                gencfg=gencfg,
                preserve_map_configs=args.preserve_map_configs,
            )
            sys.exit(0)
        if not all([x["genome"] == asset_list[0]["genome"] for x in asset_list]):
            _LOGGER.error("Build can only build assets for one genome")
            sys.exit(1)
        recipe_name = None
        if args.recipe:
            if len(asset_list) > 1:
                _LOGGER.error("Recipes cannot be specified for multi-asset builds")
                sys.exit(1)
            recipe_name = args.recipe
        if args.requirements:
            for a in asset_list:
                recipe = recipe_name or a["asset"]
                if recipe not in asset_build_packages.keys():
                    _raise_missing_recipe_error(recipe)
                _LOGGER.info("'{}' recipe requirements: ".format(recipe))
                _make_asset_build_reqs(recipe)
            sys.exit(0)

        ret = refgenie_build(
            gencfg, asset_list[0]["genome"], asset_list, recipe_name, args
        )
        if not ret:
            sys.exit(1)
        else:
            sys.exit(0)

    elif args.command == GET_ASSET_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        check = args.check_exists if args.check_exists else None
        for a in asset_list:
            _LOGGER.debug(
                "getting asset: '{}/{}.{}:{}'".format(
                    a["genome"], a["asset"], a["seek_key"], a["tag"]
                )
            )
            print(
                rgc.seek(
                    a["genome"],
                    a["asset"],
                    a["tag"],
                    a["seek_key"],
                    strict_exists=check,
                )
            )
        return

    elif args.command == GET_REMOTE_ASSET_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        if args.genome_server is not None:
            rgc.subscribe(
                urls=args.genome_server, reset=not args.append_server, no_write=True
            )
        for a in asset_list:
            _LOGGER.debug(
                "getting remote asset path: '{}/{}.{}:{}'".format(
                    a["genome"], a["asset"], a["seek_key"], a["tag"]
                )
            )
            print(
                rgc.seekr(
                    a["genome"],
                    a["asset"],
                    a["tag"],
                    a["seek_key"],
                    args.remote_class,
                )
            )
        return

    elif args.command == INSERT_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        if len(asset_list) > 1:
            raise NotImplementedError("Can only add 1 asset at a time")
        else:
            sk = args.seek_keys
            if sk:
                sk = json.loads(args.seek_keys)
            rgc.add(
                path=args.path,
                genome=asset_list[0]["genome"],
                asset=asset_list[0]["asset"],
                tag=asset_list[0]["tag"],
                seek_keys=sk,
                force=args.force,
            )

    elif args.command == PULL_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)

        # existing assets overwriting
        if args.no_overwrite:
            force = False
        elif args.force_overwrite:
            force = True
        else:
            force = None
        # large archive pulling
        if args.no_large:
            force_large = False
        elif args.pull_large:
            force_large = True
        else:
            force_large = None
        # batch mode takes precedence over other choices
        if args.batch:
            force_large = True
            force = False

        outdir = rgc.data_dir
        if not os.path.exists(outdir):
            raise MissingFolderError(outdir)
        if not perm_check_x(outdir):
            return
        if not _single_folder_writeable(outdir):
            _LOGGER.error("Insufficient permissions to write to: {}".format(outdir))
            return

        for a in asset_list:
            rgc.pull(
                a["genome"],
                a["asset"],
                a["tag"],
                force=force,
                force_large=force_large,
                size_cutoff=args.size_cutoff,
            )

    elif args.command in [LIST_LOCAL_CMD, LIST_REMOTE_CMD]:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        console = Console()
        if args.command == LIST_REMOTE_CMD:
            if args.genome_server is not None:
                rgc.subscribe(
                    urls=args.genome_server, reset=not args.append_server, no_write=True
                )
            num_servers = 0
            bad_servers = []
            for server_url in rgc[CFG_SERVERS_KEY]:
                num_servers += 1
                try:
                    table = rgc.get_asset_table(
                        genomes=args.genome, server_url=server_url
                    )
                except (DownloadJsonError, ConnectionError, MissingSchema):
                    bad_servers.append(server_url)
                    continue
                else:
                    console.print(table)
            if num_servers >= len(rgc[CFG_SERVERS_KEY]) and bad_servers:
                _LOGGER.error(
                    "Could not list assets from the following servers: {}".format(
                        bad_servers
                    )
                )
        else:
            if args.recipes:
                print(", ".join(sorted(list(asset_build_packages.keys()))))
            else:
                console.print(rgc.get_asset_table(genomes=args.genome))

    elif args.command == GETSEQ_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        print(rgc.getseq(args.genome, args.locus))

    elif args.command == REMOVE_CMD:
        force = args.force
        rgc = RefGenConf(filepath=gencfg, skip_read_lock=skip_read_lock)
        for a in asset_list:
            a["tag"] = a["tag"] or rgc.get_default_tag(
                a["genome"], a["asset"], use_existing=False
            )
            _LOGGER.debug("Determined tag for removal: {}".format(a["tag"]))
            if a["seek_key"] is not None:
                raise NotImplementedError("You can't remove a specific seek_key.")
            gat = {"genome": a["genome"], "asset": a["asset"], "tag": a["tag"]}
            try:
                if not rgc.is_asset_complete(**gat):
                    with rgc as r:
                        r.cfg_remove_assets(**gat)
                    _LOGGER.info(
                        "Removed an incomplete asset "
                        "'{genome}/{asset}:{tag}'".format(*gat)
                    )
                    return
            except (KeyError, MissingAssetError, MissingGenomeError):
                _LOGGER.info(
                    "Asset '{genome}/{asset}:{tag}' does not exist".format(**gat)
                )
                return
        if len(asset_list) > 1:
            if not query_yes_no(
                "Are you sure you want to remove {} assets?".format(len(asset_list))
            ):
                _LOGGER.info("Action aborted by the user")
                return
            force = True
        for a in asset_list:
            rgc.remove(genome=a["genome"], asset=a["asset"], tag=a["tag"], force=force)

    elif args.command == TAG_CMD:
        rgc = RefGenConf(filepath=gencfg, skip_read_lock=skip_read_lock)
        if len(asset_list) > 1:
            raise NotImplementedError("Can only tag 1 asset at a time")
        if args.default:
            # set the default tag and exit
            with rgc as r:
                r.set_default_pointer(a["genome"], a["asset"], a["tag"], True)
            sys.exit(0)
        rgc.tag(a["genome"], a["asset"], a["tag"], args.tag, force=args.force)

    elif args.command == ID_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        if len(asset_list) == 1:
            g, a = asset_list[0]["genome"], asset_list[0]["asset"]
            t = asset_list[0]["tag"] or rgc.get_default_tag(g, a)
            print(rgc.id(g, a, t))
            return
        for asset in asset_list:
            g, a = asset["genome"], asset["asset"]
            t = asset["tag"] or rgc.get_default_tag(g, a)
            print("{}/{}:{},".format(g, a, t) + rgc.id(g, a, t))
        return
    elif args.command == SUBSCRIBE_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        rgc.subscribe(urls=args.genome_server, reset=args.reset)
        return
    elif args.command == UNSUBSCRIBE_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        rgc.unsubscribe(urls=args.genome_server)
        return
    elif args.command == ALIAS_CMD:
        rgc = RefGenConf(filepath=gencfg, skip_read_lock=skip_read_lock)
        if args.subcommand == ALIAS_GET_CMD:
            if args.aliases is not None:
                for a in args.aliases:
                    print(rgc.get_genome_alias_digest(alias=a))
                return
            console = Console()
            console.print(rgc.genome_aliases_table)

        if args.subcommand == ALIAS_SET_CMD:
            rgc.set_genome_alias(
                digest=args.digest,
                genome=args.aliases,
                reset_digest=args.reset,
                create_genome=args.force,
            )
            return
        elif args.subcommand == ALIAS_REMOVE_CMD:
            rgc.remove_genome_aliases(digest=args.digest, aliases=args.aliases)
            return

    elif args.command == COMPARE_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        res = rgc.compare(
            args.genome1[0], args.genome2[0], explain=not args.no_explanation
        )
        if args.no_explanation:
            print(res)
        if args.flag_meanings:
            from refgenconf.seqcol import FLAGS
            from rich.table import Table

            _LOGGER.info("\n")
            codes = sorted(FLAGS.keys())
            table = Table(title="Compatibility flags")
            table.add_column("Code")
            table.add_column("Indication")
            for code in codes:
                table.add_row(str(code), FLAGS[code])
            console = Console()
            console.print(table)

    elif args.command == UPGRADE_CMD:
        upgrade_config(
            target_version=args.target_version, filepath=gencfg, force=args.force
        )

    elif args.command == POPULATE_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        process_populate(pop_fun=rgc.populate, file_path=args.file)

    elif args.command == POPULATE_REMOTE_CMD:
        rgc = RefGenConf(filepath=gencfg, writable=False, skip_read_lock=skip_read_lock)
        if args.genome_server is not None:
            rgc.subscribe(
                urls=args.genome_server, reset=not args.append_server, no_write=True
            )
        pop_fun = partial(rgc.populater, remote_class=args.remote_class)
        process_populate(pop_fun=pop_fun, file_path=args.file)
Example #29
0
def test_emoji_switch():
    """Test emoji can be disabled."""
    console = Console(file=StringIO(), emoji=False)
    console.print(":+1:")
    assert console.file.getvalue() == ":+1:\n"
Example #30
0
def test_soft_wrap():
    console = Console(file=io.StringIO(), width=20, soft_wrap=True)
    console.print("foo " * 10)
    assert console.file.getvalue() == "foo " * 20