File size: 5,486 Bytes
b93364a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""Settings Controller Module."""

import argparse
from functools import partial, update_wrapper
from types import MethodType
from typing import List, Literal, Optional, get_origin

from openbb_cli.config.menu_text import MenuText
from openbb_cli.controllers.base_controller import BaseController
from openbb_cli.models.settings import SettingGroups
from openbb_cli.session import Session

session = Session()


class SettingsController(BaseController):
    """Settings Controller class."""

    _COMMANDS = {
        v.json_schema_extra.get("command"): {
            "command": (v.json_schema_extra or {}).get("command"),
            "group": (v.json_schema_extra or {}).get("group"),
            "description": v.description,
            "annotation": v.annotation,
            "field_name": k,
        }
        for k, v in sorted(
            session.settings.model_fields.items(),
            key=lambda item: (item[1].json_schema_extra or {}).get("command", ""),
        )
        if v.json_schema_extra
    }
    CHOICES_COMMANDS: List[str] = list(_COMMANDS.keys())
    PATH = "/settings/"
    CHOICES_GENERATION = True

    def __init__(self, queue: Optional[List[str]] = None):
        """Initialize the Constructor."""
        super().__init__(queue)
        for cmd, field in self._COMMANDS.items():
            group = field.get("group")
            if group == SettingGroups.feature_flags:
                self._generate_command(cmd, field, "toggle")
            elif group == SettingGroups.preferences:
                self._generate_command(cmd, field, "set")
        self.update_completer(self.choices_default)

    def print_help(self):
        """Print help."""
        mt = MenuText("settings/")
        mt.add_info("Feature Flags")
        for k, f in self._COMMANDS.items():
            if f.get("group") == SettingGroups.feature_flags:
                mt.add_setting(
                    name=k,
                    status=getattr(session.settings, f["field_name"]),
                    description=f["description"],
                )
        mt.add_raw("\n")
        mt.add_info("Preferences")
        for k, f in self._COMMANDS.items():
            if f.get("group") == SettingGroups.preferences:
                mt.add_cmd(
                    name=k,
                    description=f["description"],
                )
        session.console.print(text=mt.menu_text, menu="Settings")

    def _generate_command(
        self, cmd_name: str, field: dict, action_type: Literal["toggle", "set"]
    ):
        """Generate command call."""

        def _toggle(self, other_args: List[str], field=field) -> None:
            """Toggle setting value."""
            field_name = field["field_name"]
            parser = argparse.ArgumentParser(
                formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                prog=field["command"],
                description=field["description"],
                add_help=False,
            )
            ns_parser, _ = self.parse_simple_args(parser, other_args)
            if ns_parser:
                session.settings.set_item(
                    field_name, not getattr(session.settings, field_name)
                )

        def _set(self, other_args: List[str], field=field) -> None:
            """Set preference value."""
            field_name = field["field_name"]
            annotation = field["annotation"]
            command = field["command"]
            type_ = str if get_origin(annotation) is Literal else annotation
            choices = None
            if get_origin(annotation) is Literal:
                choices = annotation.__args__
            elif command == "console_style":
                # To have updated choices for console style
                choices = session.style.available_styles
            parser = argparse.ArgumentParser(
                formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                prog=command,
                description=field["description"],
                add_help=False,
            )
            parser.add_argument(
                "-v",
                "--value",
                dest="value",
                action="store",
                required=False,
                type=type_,  # type: ignore[arg-type]
                choices=choices,
            )
            ns_parser, _ = self.parse_simple_args(parser, other_args)
            if ns_parser:
                if ns_parser.value:
                    # Console style is applied immediately
                    if command == "console_style":
                        session.style.apply(ns_parser.value)
                    session.settings.set_item(field_name, ns_parser.value)
                    session.console.print(
                        f"[info]Current value:[/info] {getattr(session.settings, field_name)}"
                    )
                elif not other_args:
                    session.console.print(
                        f"[info]Current value:[/info] {getattr(session.settings, field_name)}"
                    )

        action = None
        if action_type == "toggle":
            action = _toggle
        elif action_type == "set":
            action = _set
        else:
            raise ValueError(f"Action type '{action_type}' not allowed.")

        bound_method = update_wrapper(
            wrapper=partial(MethodType(action, self), field=field), wrapped=action
        )
        setattr(self, f"call_{cmd_name}", bound_method)