File: group_extractors.py

package info (click to toggle)
python-cyclopts 3.12.0-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,288 kB
  • sloc: python: 11,445; makefile: 24
file content (94 lines) | stat: -rw-r--r-- 2,883 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
from typing import TYPE_CHECKING, Any, Union

from cyclopts.group import Group

if TYPE_CHECKING:
    from cyclopts.core import App


def _create_or_append(
    group_mapping: list[tuple[Group, list[Any]]],
    group: Union[str, Group],
    element: Any,
):
    # updates group_mapping inplace.
    if isinstance(group, str):
        group = Group(group)
    elif isinstance(group, Group):
        pass
    else:
        raise TypeError

    for mapping in group_mapping:
        if mapping[0].name == group.name:
            mapping[1].append(element)
            break
    else:
        group_mapping.append((group, [element]))


def groups_from_app(app: "App") -> list[tuple[Group, list["App"]]]:
    """Extract Group/App association from all commands of ``app``.

    Returns
    -------
    list
        List of items where each item is a tuple containing:

        * :class:`.Group` - The group

        * ``list[App]`` - The list of app subcommands within the group.
    """
    assert not isinstance(app.group_commands, str)
    group_commands = app.group_commands or Group.create_default_commands()
    group_mapping: list[tuple[Group, list[App]]] = [
        (group_commands, []),
    ]

    subapps = list(app.subapps)

    # 2 iterations need to be performed:
    # 1. Extract out all Group objects as they may have additional configuration.
    # 2. Assign/Create Groups out of the strings, as necessary.
    for subapp in subapps:
        assert isinstance(subapp.group, tuple)
        for group in subapp.group:
            if isinstance(group, Group):
                for mapping in group_mapping:
                    if mapping[0] is group:
                        break
                    elif mapping[0].name == group.name:
                        raise ValueError(f'Command Group "{group.name}" already exists.')
                else:
                    group_mapping.append((group, []))

    for subapp in subapps:
        if subapp.group:
            assert isinstance(subapp.group, tuple)
            for group in subapp.group:
                _create_or_append(group_mapping, group, subapp)
        else:
            _create_or_append(group_mapping, app.group_commands or Group.create_default_commands(), subapp)

    # Remove the empty groups
    group_mapping = [x for x in group_mapping if x[1]]

    # Sort alphabetically by name
    group_mapping.sort(key=lambda x: x[0].name)

    return group_mapping


def inverse_groups_from_app(input_app: "App") -> list[tuple["App", list[Group]]]:
    out = []
    seen_apps = []
    for group, apps in groups_from_app(input_app):
        for app in apps:
            try:
                index = seen_apps.index(app)
            except ValueError:
                index = len(out)
                out.append((app, []))
                seen_apps.append(app)
            out[index][1].append(group)
    return out