muscles-cli 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- muscles_cli-1.0.0/PKG-INFO +165 -0
- muscles_cli-1.0.0/README.md +140 -0
- muscles_cli-1.0.0/pyproject.toml +32 -0
- muscles_cli-1.0.0/src/muscles/cli/Makefile +26 -0
- muscles_cli-1.0.0/src/muscles/cli/__about__.py +6 -0
- muscles_cli-1.0.0/src/muscles/cli/__init__.py +66 -0
- muscles_cli-1.0.0/src/muscles/cli/__main__.py +5 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/__init__.py +6 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/cli.py +44 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/colory.py +15 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/command.py +778 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/constants.py +3 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/error_handler.py +6 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/func.py +221 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/instance.py +47 -0
- muscles_cli-1.0.0/src/muscles/cli/cli/strategy.py +111 -0
- muscles_cli-1.0.0/src/muscles/cli/providers.py +198 -0
- muscles_cli-1.0.0/src/muscles/cli/streaming.py +50 -0
- muscles_cli-1.0.0/src/muscles/cli/tooling.py +927 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: muscles-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Muscles CLI runtime for shared command routing and strategy execution
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Denis B.
|
|
7
|
+
Author-email: denis@butko.info
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Dist: dnspython (==2.6.1)
|
|
17
|
+
Requires-Dist: greenlet (==3.0.2)
|
|
18
|
+
Requires-Dist: jsonschema (==4.16.0)
|
|
19
|
+
Requires-Dist: muscles (>=1.0.0rc1,<2.0.0)
|
|
20
|
+
Requires-Dist: pyyaml (>=6.0.0,<6.1.0)
|
|
21
|
+
Requires-Dist: watchdog (>=4.0.0,<5.0.0)
|
|
22
|
+
Requires-Dist: werkzeug (==2.1.1)
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Muscles CLI
|
|
26
|
+
|
|
27
|
+
`muscles-cli` is the console runtime for Muscles. It uses the same application
|
|
28
|
+
shape as the HTTP runtimes: an `ApplicationMeta` class owns a `Context`, and the
|
|
29
|
+
context delegates execution to `CliStrategy`.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install muscles-cli
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Canonical ecosystem install matrix is documented in core:
|
|
38
|
+
[Muscles installation matrix](https://github.com/butkoden/muscles/blob/master/docs/installation.md).
|
|
39
|
+
|
|
40
|
+
## Related Repositories
|
|
41
|
+
|
|
42
|
+
- [`muscles`](https://github.com/butkoden/muscles) - core contracts, actions, inspect output and canonical documentation.
|
|
43
|
+
- [`muscles-asgi`](https://github.com/butkoden/muscles-asgi) - ASGI runtime generated projects can target.
|
|
44
|
+
- [`muscles-wsgi`](https://github.com/butkoden/muscles-wsgi) - WSGI runtime generated projects can target.
|
|
45
|
+
- [`muscles-mcp`](https://github.com/butkoden/muscles-mcp) - MCP projection over the same action contracts.
|
|
46
|
+
- [`muscles-benchmarks`](https://github.com/butkoden/muscles-benchmarks) - CLI regression and architecture checks.
|
|
47
|
+
|
|
48
|
+
## Project Scaffolding
|
|
49
|
+
|
|
50
|
+
Use canonical command `muscles new`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
muscles new demo --runtime asgi
|
|
54
|
+
muscles new demo --runtime wsgi
|
|
55
|
+
muscles new demo --runtime cli
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
|
|
60
|
+
- `muscular new` is not a canonical command.
|
|
61
|
+
- Existing non-empty directory is rejected unless `--force` is used.
|
|
62
|
+
|
|
63
|
+
## AI Workflow Commands
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
muscles capabilities --json
|
|
67
|
+
muscles inspect --json --app app.application:App
|
|
68
|
+
muscles action list --app app.application:App --json
|
|
69
|
+
muscles action inspect bookings.echo --app app.application:App --json
|
|
70
|
+
muscles action run bookings.echo --app app.application:App --payload-json '{"title":"Call"}' --json
|
|
71
|
+
muscles routes --app app.application:App
|
|
72
|
+
muscles schemas --app app.application:App
|
|
73
|
+
muscles rules --app app.application:App
|
|
74
|
+
muscles cli --app app.application:App
|
|
75
|
+
muscles generate page Home --with-tests
|
|
76
|
+
muscles doctor --json
|
|
77
|
+
muscles test --doctor
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from muscles import ApplicationMeta, Context, cli
|
|
84
|
+
from muscles.cli import CliStrategy
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class App(metaclass=ApplicationMeta):
|
|
88
|
+
context = Context(CliStrategy)
|
|
89
|
+
|
|
90
|
+
def run(self, *args):
|
|
91
|
+
return self.context.execute(*args, shutup=True)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@cli.group()
|
|
95
|
+
def bookings(*args):
|
|
96
|
+
"""Booking commands."""
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@bookings.command(command_name="remove")
|
|
101
|
+
def remove_booking(*args):
|
|
102
|
+
booking_id = args[0]
|
|
103
|
+
return f"removed {booking_id}"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
app = App()
|
|
107
|
+
assert app.run("bookings", "remove", "1") == "removed 1"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Routing Model
|
|
111
|
+
|
|
112
|
+
Groups and commands form a tree. That makes CLI routing close to HTTP routing:
|
|
113
|
+
|
|
114
|
+
- `bookings remove 1` is a nested route with an argument;
|
|
115
|
+
- `bookings/list` can be normalized by an application before calling the CLI;
|
|
116
|
+
- groups can have handlers, but returning `True` lets execution continue to a
|
|
117
|
+
child command.
|
|
118
|
+
|
|
119
|
+
More detail: [docs/routing.md](docs/routing.md).
|
|
120
|
+
|
|
121
|
+
## Core Stream Output
|
|
122
|
+
|
|
123
|
+
English: CLI progress output uses core `StreamEvent` items from
|
|
124
|
+
`StreamResult`. `render_stream_result()` can print human-readable progress/log
|
|
125
|
+
and result lines, or machine-readable JSON lines. The CLI layer only owns
|
|
126
|
+
presentation and exit code mapping; stream semantics stay in `muscles.core`.
|
|
127
|
+
|
|
128
|
+
Русский: CLI progress output использует core `StreamEvent` из `StreamResult`.
|
|
129
|
+
`render_stream_result()` может печатать human-readable progress/log/result
|
|
130
|
+
строки или machine-readable JSON lines. CLI слой отвечает только за presentation
|
|
131
|
+
и exit code mapping; stream semantics остаётся в `muscles.core`.
|
|
132
|
+
|
|
133
|
+
## Arguments
|
|
134
|
+
|
|
135
|
+
Use `@cli.argument()` for named arguments and `@cli.flag()` for boolean flags.
|
|
136
|
+
Required prompted arguments use `input()` or `getpass.getpass()` when hidden.
|
|
137
|
+
|
|
138
|
+
For nested commands, define options on the parent group object:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
@cli.group(command_name="bookings")
|
|
142
|
+
def bookings(*args):
|
|
143
|
+
return True
|
|
144
|
+
|
|
145
|
+
@bookings.command(command_name="list")
|
|
146
|
+
@bookings.argument("--limit", nargs=1, default="25")
|
|
147
|
+
def bookings_list(*args, limit):
|
|
148
|
+
return limit
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Canonical invocations for benchmark/automation scripts:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
bookings list --limit 10
|
|
155
|
+
bookings list --limit=10
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
Run tests with the core package on `PYTHONPATH`:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
PYTHONPATH=../muscles/src:src python -m pytest -q
|
|
164
|
+
```
|
|
165
|
+
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Muscles CLI
|
|
2
|
+
|
|
3
|
+
`muscles-cli` is the console runtime for Muscles. It uses the same application
|
|
4
|
+
shape as the HTTP runtimes: an `ApplicationMeta` class owns a `Context`, and the
|
|
5
|
+
context delegates execution to `CliStrategy`.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install muscles-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Canonical ecosystem install matrix is documented in core:
|
|
14
|
+
[Muscles installation matrix](https://github.com/butkoden/muscles/blob/master/docs/installation.md).
|
|
15
|
+
|
|
16
|
+
## Related Repositories
|
|
17
|
+
|
|
18
|
+
- [`muscles`](https://github.com/butkoden/muscles) - core contracts, actions, inspect output and canonical documentation.
|
|
19
|
+
- [`muscles-asgi`](https://github.com/butkoden/muscles-asgi) - ASGI runtime generated projects can target.
|
|
20
|
+
- [`muscles-wsgi`](https://github.com/butkoden/muscles-wsgi) - WSGI runtime generated projects can target.
|
|
21
|
+
- [`muscles-mcp`](https://github.com/butkoden/muscles-mcp) - MCP projection over the same action contracts.
|
|
22
|
+
- [`muscles-benchmarks`](https://github.com/butkoden/muscles-benchmarks) - CLI regression and architecture checks.
|
|
23
|
+
|
|
24
|
+
## Project Scaffolding
|
|
25
|
+
|
|
26
|
+
Use canonical command `muscles new`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
muscles new demo --runtime asgi
|
|
30
|
+
muscles new demo --runtime wsgi
|
|
31
|
+
muscles new demo --runtime cli
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Notes:
|
|
35
|
+
|
|
36
|
+
- `muscular new` is not a canonical command.
|
|
37
|
+
- Existing non-empty directory is rejected unless `--force` is used.
|
|
38
|
+
|
|
39
|
+
## AI Workflow Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
muscles capabilities --json
|
|
43
|
+
muscles inspect --json --app app.application:App
|
|
44
|
+
muscles action list --app app.application:App --json
|
|
45
|
+
muscles action inspect bookings.echo --app app.application:App --json
|
|
46
|
+
muscles action run bookings.echo --app app.application:App --payload-json '{"title":"Call"}' --json
|
|
47
|
+
muscles routes --app app.application:App
|
|
48
|
+
muscles schemas --app app.application:App
|
|
49
|
+
muscles rules --app app.application:App
|
|
50
|
+
muscles cli --app app.application:App
|
|
51
|
+
muscles generate page Home --with-tests
|
|
52
|
+
muscles doctor --json
|
|
53
|
+
muscles test --doctor
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from muscles import ApplicationMeta, Context, cli
|
|
60
|
+
from muscles.cli import CliStrategy
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class App(metaclass=ApplicationMeta):
|
|
64
|
+
context = Context(CliStrategy)
|
|
65
|
+
|
|
66
|
+
def run(self, *args):
|
|
67
|
+
return self.context.execute(*args, shutup=True)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@cli.group()
|
|
71
|
+
def bookings(*args):
|
|
72
|
+
"""Booking commands."""
|
|
73
|
+
return True
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@bookings.command(command_name="remove")
|
|
77
|
+
def remove_booking(*args):
|
|
78
|
+
booking_id = args[0]
|
|
79
|
+
return f"removed {booking_id}"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
app = App()
|
|
83
|
+
assert app.run("bookings", "remove", "1") == "removed 1"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Routing Model
|
|
87
|
+
|
|
88
|
+
Groups and commands form a tree. That makes CLI routing close to HTTP routing:
|
|
89
|
+
|
|
90
|
+
- `bookings remove 1` is a nested route with an argument;
|
|
91
|
+
- `bookings/list` can be normalized by an application before calling the CLI;
|
|
92
|
+
- groups can have handlers, but returning `True` lets execution continue to a
|
|
93
|
+
child command.
|
|
94
|
+
|
|
95
|
+
More detail: [docs/routing.md](docs/routing.md).
|
|
96
|
+
|
|
97
|
+
## Core Stream Output
|
|
98
|
+
|
|
99
|
+
English: CLI progress output uses core `StreamEvent` items from
|
|
100
|
+
`StreamResult`. `render_stream_result()` can print human-readable progress/log
|
|
101
|
+
and result lines, or machine-readable JSON lines. The CLI layer only owns
|
|
102
|
+
presentation and exit code mapping; stream semantics stay in `muscles.core`.
|
|
103
|
+
|
|
104
|
+
Русский: CLI progress output использует core `StreamEvent` из `StreamResult`.
|
|
105
|
+
`render_stream_result()` может печатать human-readable progress/log/result
|
|
106
|
+
строки или machine-readable JSON lines. CLI слой отвечает только за presentation
|
|
107
|
+
и exit code mapping; stream semantics остаётся в `muscles.core`.
|
|
108
|
+
|
|
109
|
+
## Arguments
|
|
110
|
+
|
|
111
|
+
Use `@cli.argument()` for named arguments and `@cli.flag()` for boolean flags.
|
|
112
|
+
Required prompted arguments use `input()` or `getpass.getpass()` when hidden.
|
|
113
|
+
|
|
114
|
+
For nested commands, define options on the parent group object:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
@cli.group(command_name="bookings")
|
|
118
|
+
def bookings(*args):
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
@bookings.command(command_name="list")
|
|
122
|
+
@bookings.argument("--limit", nargs=1, default="25")
|
|
123
|
+
def bookings_list(*args, limit):
|
|
124
|
+
return limit
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Canonical invocations for benchmark/automation scripts:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
bookings list --limit 10
|
|
131
|
+
bookings list --limit=10
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
Run tests with the core package on `PYTHONPATH`:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
PYTHONPATH=../muscles/src:src python -m pytest -q
|
|
140
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["poetry-core>=1.0.0"]
|
|
3
|
+
build-backend = "poetry.core.masonry.api"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
[tool.poetry]
|
|
7
|
+
name = "muscles-cli"
|
|
8
|
+
version = "1.0.0"
|
|
9
|
+
description = "Muscles CLI runtime for shared command routing and strategy execution"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
authors = ["Denis B. <denis@butko.info>"]
|
|
12
|
+
license = "MIT"
|
|
13
|
+
packages = [{include = "muscles", from = "src"}]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
[tool.poetry.dependencies]
|
|
17
|
+
python = ">=3.10,<4.0"
|
|
18
|
+
muscles = ">=1.0.0rc1,<2.0.0"
|
|
19
|
+
watchdog = "^4.0.0"
|
|
20
|
+
dnspython = "==2.6.1"
|
|
21
|
+
pyyaml = "~=6.0.0"
|
|
22
|
+
werkzeug = "==2.1.1"
|
|
23
|
+
greenlet = "==3.0.2"
|
|
24
|
+
jsonschema = "==4.16.0"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
[tool.poetry.dev-dependencies]
|
|
28
|
+
pytest = "==7.1.3"
|
|
29
|
+
setuptools = "==69.0.2"
|
|
30
|
+
|
|
31
|
+
[tool.poetry.scripts]
|
|
32
|
+
muscles = "muscles.cli.tooling:main"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Makefile
|
|
2
|
+
|
|
3
|
+
start:
|
|
4
|
+
docker-compose up -d
|
|
5
|
+
docker exec -it butkoinfo_core_1 bash
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
stop:
|
|
9
|
+
docker-compose up -d
|
|
10
|
+
docker exec -it butkoinfo-core-1 bash
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
console:
|
|
14
|
+
docker exec -it butkoinfo_core_1 bash
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logs:
|
|
18
|
+
docker-compose logs
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
develop:
|
|
22
|
+
#docker exec -it butkoinfo_core_1 pipenv install
|
|
23
|
+
pipenv run python setup.py develop
|
|
24
|
+
pipenv install
|
|
25
|
+
|
|
26
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from .cli import Colors
|
|
2
|
+
from .cli import Command
|
|
3
|
+
from .cli import Argument
|
|
4
|
+
from .cli import Group
|
|
5
|
+
from .cli import Console
|
|
6
|
+
from .cli import cli
|
|
7
|
+
from .cli import argsparse
|
|
8
|
+
from .cli import CliStrategy
|
|
9
|
+
from .cli import ConsoleErrorHandler
|
|
10
|
+
from .streaming import CliStreamRenderResult
|
|
11
|
+
from .streaming import render_stream_result
|
|
12
|
+
from .tooling import build_capabilities_payload
|
|
13
|
+
from .tooling import build_inspection_payload
|
|
14
|
+
from .tooling import detect_project_root
|
|
15
|
+
from .tooling import generate_artifact
|
|
16
|
+
from .tooling import load_app_from_entrypoint
|
|
17
|
+
from .tooling import main
|
|
18
|
+
from .tooling import run_doctor
|
|
19
|
+
from .tooling import run_project_tests
|
|
20
|
+
from .tooling import scaffold_project
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_TOOLING_EXPORTS = {
|
|
24
|
+
"scaffold_project",
|
|
25
|
+
"main",
|
|
26
|
+
"build_capabilities_payload",
|
|
27
|
+
"load_app_from_entrypoint",
|
|
28
|
+
"build_inspection_payload",
|
|
29
|
+
"generate_artifact",
|
|
30
|
+
"detect_project_root",
|
|
31
|
+
"run_doctor",
|
|
32
|
+
"run_project_tests",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def __getattr__(name):
|
|
37
|
+
if name in _TOOLING_EXPORTS:
|
|
38
|
+
import importlib
|
|
39
|
+
|
|
40
|
+
tooling = importlib.import_module(".tooling", __name__)
|
|
41
|
+
return getattr(tooling, name)
|
|
42
|
+
raise AttributeError(name)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = (
|
|
46
|
+
"Colors",
|
|
47
|
+
"Command",
|
|
48
|
+
"Argument",
|
|
49
|
+
"Group",
|
|
50
|
+
"Console",
|
|
51
|
+
"cli",
|
|
52
|
+
"argsparse",
|
|
53
|
+
"CliStrategy",
|
|
54
|
+
"ConsoleErrorHandler",
|
|
55
|
+
"scaffold_project",
|
|
56
|
+
"build_capabilities_payload",
|
|
57
|
+
"load_app_from_entrypoint",
|
|
58
|
+
"build_inspection_payload",
|
|
59
|
+
"generate_artifact",
|
|
60
|
+
"detect_project_root",
|
|
61
|
+
"run_doctor",
|
|
62
|
+
"run_project_tests",
|
|
63
|
+
"CliStreamRenderResult",
|
|
64
|
+
"render_stream_result",
|
|
65
|
+
"main",
|
|
66
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CliCommand(ABC):
|
|
7
|
+
"""
|
|
8
|
+
Интерфейс консольной команды или группы
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
_key = None
|
|
13
|
+
_parent = None
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def parent(self) -> CliCommand | None:
|
|
17
|
+
return self._parent
|
|
18
|
+
|
|
19
|
+
@parent.setter
|
|
20
|
+
def parent(self, parent: CliCommand | None):
|
|
21
|
+
self._parent = parent
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def key(self) -> list[str]:
|
|
25
|
+
return self._key or []
|
|
26
|
+
|
|
27
|
+
@key.setter
|
|
28
|
+
def key(self, key) -> None:
|
|
29
|
+
self._key = key
|
|
30
|
+
|
|
31
|
+
def add(self, command) -> None:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def remove(self, command) -> None:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def execute(self, *args, **kwargs) -> Any:
|
|
39
|
+
"""
|
|
40
|
+
Базовый Компонент может сам реализовать некоторое поведение по умолчанию
|
|
41
|
+
или поручить это конкретным классам, объявив метод, содержащий поведение
|
|
42
|
+
абстрактным.
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Colors:
|
|
5
|
+
HEADER = '\033[95m'
|
|
6
|
+
OKBLUE = '\033[94m'
|
|
7
|
+
OKCYAN = '\033[96m'
|
|
8
|
+
OKGREEN = '\033[92m'
|
|
9
|
+
WARNING = '\033[93m'
|
|
10
|
+
FAIL = '\033[91m'
|
|
11
|
+
ENDC = '\033[0m'
|
|
12
|
+
BOLD = '\033[1m'
|
|
13
|
+
UNDERLINE = '\033[4m'
|
|
14
|
+
|
|
15
|
+
|