mcp-proxy-adapter 2.1.2__py3-none-any.whl → 2.1.4__py3-none-any.whl
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.
- {examples → mcp_proxy_adapter/examples}/openapi_server.py +35 -7
- {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.4.dist-info}/METADATA +98 -2
- mcp_proxy_adapter-2.1.4.dist-info/RECORD +28 -0
- mcp_proxy_adapter-2.1.4.dist-info/top_level.txt +1 -0
- docs/README.md +0 -172
- docs/README_ru.md +0 -172
- docs/architecture.md +0 -251
- docs/architecture_ru.md +0 -343
- docs/command_development.md +0 -250
- docs/command_development_ru.md +0 -593
- docs/deployment.md +0 -251
- docs/deployment_ru.md +0 -1298
- docs/examples.md +0 -254
- docs/examples_ru.md +0 -401
- docs/mcp_proxy_adapter.md +0 -251
- docs/mcp_proxy_adapter_ru.md +0 -405
- docs/quickstart.md +0 -251
- docs/quickstart_ru.md +0 -397
- docs/testing.md +0 -255
- docs/testing_ru.md +0 -469
- docs/validation_ru.md +0 -287
- examples/mcp_proxy_config.json +0 -175
- mcp_proxy_adapter-2.1.2.dist-info/RECORD +0 -61
- mcp_proxy_adapter-2.1.2.dist-info/top_level.txt +0 -5
- scripts/code_analyzer/code_analyzer.py +0 -328
- scripts/code_analyzer/register_commands.py +0 -446
- scripts/publish.py +0 -85
- tests/conftest.py +0 -12
- tests/test_adapter.py +0 -529
- tests/test_adapter_coverage.py +0 -274
- tests/test_basic_dispatcher.py +0 -169
- tests/test_command_registry.py +0 -328
- tests/test_examples.py +0 -32
- tests/test_mcp_proxy_adapter.py +0 -568
- tests/test_mcp_proxy_adapter_basic.py +0 -262
- tests/test_part1.py +0 -348
- tests/test_part2.py +0 -524
- tests/test_schema.py +0 -358
- tests/test_simple_adapter.py +0 -251
- {examples → mcp_proxy_adapter/examples}/analyze_config.py +0 -0
- {examples → mcp_proxy_adapter/examples}/basic_integration.py +0 -0
- {examples → mcp_proxy_adapter/examples}/docstring_and_schema_example.py +0 -0
- {examples → mcp_proxy_adapter/examples}/extension_example.py +0 -0
- {examples → mcp_proxy_adapter/examples}/help_best_practices.py +0 -0
- {examples → mcp_proxy_adapter/examples}/help_usage.py +0 -0
- {examples → mcp_proxy_adapter/examples}/mcp_proxy_client.py +0 -0
- {examples → mcp_proxy_adapter/examples}/project_structure_example.py +0 -0
- {examples → mcp_proxy_adapter/examples}/testing_example.py +0 -0
- {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.4.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.4.dist-info}/licenses/LICENSE +0 -0
docs/architecture.md
DELETED
@@ -1,251 +0,0 @@
|
|
1
|
-
# Command Registry Architecture
|
2
|
-
|
3
|
-
This document describes the architecture of the Command Registry system, its key components, their interactions, and extension principles.
|
4
|
-
|
5
|
-
## Architecture Overview
|
6
|
-
|
7
|
-
Command Registry is a modular system built around the concept of centralized command storage and management. The architecture ensures flexibility, extensibility, and adherence to SOLID principles.
|
8
|
-
|
9
|
-
Key system capabilities:
|
10
|
-
|
11
|
-
1. **Defining commands as Python functions** using type hints and docstrings
|
12
|
-
2. **Metadata extraction** from function signatures and their documentation
|
13
|
-
3. **Command registration** in a central registry
|
14
|
-
4. **Providing a unified interface** for command execution
|
15
|
-
5. **API documentation generation** based on command metadata
|
16
|
-
6. **Command export** through various protocols (REST, JSON-RPC, CLI, etc.)
|
17
|
-
|
18
|
-
## System Components
|
19
|
-
|
20
|
-

|
21
|
-
|
22
|
-
### Core Components:
|
23
|
-
|
24
|
-
1. **Command Definition** - Command definition (Python function with type hints and docstrings)
|
25
|
-
2. **Dispatcher Component** - Command dispatcher responsible for registration and execution
|
26
|
-
3. **Metadata Extractor** - Extracts metadata from docstrings and function signatures
|
27
|
-
4. **Protocol Adapter** - Adapter for exporting commands through various protocols
|
28
|
-
|
29
|
-
### CommandRegistry
|
30
|
-
|
31
|
-
The central system component that:
|
32
|
-
|
33
|
-
- Initializes and configures dispatchers
|
34
|
-
- Provides an interface for command registration
|
35
|
-
- Manages command metadata
|
36
|
-
- Coordinates interaction between components
|
37
|
-
|
38
|
-
## Command Lifecycle
|
39
|
-
|
40
|
-
### 1. Command Definition
|
41
|
-
|
42
|
-
```python
|
43
|
-
def calculate_total(
|
44
|
-
prices: List[float],
|
45
|
-
discount: float = 0.0,
|
46
|
-
tax_rate: float = 0.0
|
47
|
-
) -> float:
|
48
|
-
"""
|
49
|
-
Calculates total cost including discount and tax.
|
50
|
-
|
51
|
-
Args:
|
52
|
-
prices: List of item prices
|
53
|
-
discount: Discount percentage (0-100)
|
54
|
-
tax_rate: Tax rate percentage (0-100)
|
55
|
-
|
56
|
-
Returns:
|
57
|
-
Total cost including discount and tax
|
58
|
-
"""
|
59
|
-
subtotal = sum(prices)
|
60
|
-
discounted = subtotal * (1 - discount / 100)
|
61
|
-
total = discounted * (1 + tax_rate / 100)
|
62
|
-
return round(total, 2)
|
63
|
-
```
|
64
|
-
|
65
|
-
### 2. Command Registration
|
66
|
-
|
67
|
-
```python
|
68
|
-
from command_registry import CommandRegistry
|
69
|
-
from command_registry.dispatchers import CommandDispatcher
|
70
|
-
|
71
|
-
# Create command registry
|
72
|
-
registry = CommandRegistry(CommandDispatcher())
|
73
|
-
|
74
|
-
# Register command
|
75
|
-
registry.register_command("calculate_total", calculate_total)
|
76
|
-
```
|
77
|
-
|
78
|
-
### 3. Command Execution
|
79
|
-
|
80
|
-
```python
|
81
|
-
# Execute command
|
82
|
-
result = registry.execute(
|
83
|
-
"calculate_total",
|
84
|
-
{
|
85
|
-
"prices": [10.0, 20.0, 30.0],
|
86
|
-
"discount": 10.0,
|
87
|
-
"tax_rate": 7.0
|
88
|
-
}
|
89
|
-
)
|
90
|
-
print(result) # 57.33
|
91
|
-
```
|
92
|
-
|
93
|
-
### 4. API Export
|
94
|
-
|
95
|
-
```python
|
96
|
-
from fastapi import FastAPI
|
97
|
-
from command_registry.adapters import RESTAdapter
|
98
|
-
|
99
|
-
app = FastAPI()
|
100
|
-
adapter = RESTAdapter(registry)
|
101
|
-
adapter.register_endpoints(app)
|
102
|
-
```
|
103
|
-
|
104
|
-
## Data Flow Diagrams
|
105
|
-
|
106
|
-
### Command Registration Process
|
107
|
-
|
108
|
-
```
|
109
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
110
|
-
│ │ │ │ │ │
|
111
|
-
│ Python Function├─────►│ Metadata Extractor ├─────►│ Metadata │
|
112
|
-
│ │ │ │ │ │
|
113
|
-
└─────────────────┘ └────────────────────┘ └────────┬────────┘
|
114
|
-
│
|
115
|
-
▼
|
116
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
117
|
-
│ │ │ │ │ │
|
118
|
-
│ CommandRegistry│◄─────┤ Data Validation │◄─────┤ Parameters │
|
119
|
-
│ │ │ │ │ │
|
120
|
-
└────────┬────────┘ └────────────────────┘ └─────────────────┘
|
121
|
-
│
|
122
|
-
▼
|
123
|
-
┌─────────────────┐
|
124
|
-
│ │
|
125
|
-
│ Dispatcher │
|
126
|
-
│ │
|
127
|
-
└─────────────────┘
|
128
|
-
```
|
129
|
-
|
130
|
-
### Command Execution Process
|
131
|
-
|
132
|
-
```
|
133
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
134
|
-
│ │ │ │ │ │
|
135
|
-
│ Command Name │ │ │ │ Parameter │
|
136
|
-
│ + Parameters ├─────►│ CommandRegistry ├─────►│ Validation │
|
137
|
-
│ │ │ │ │ │
|
138
|
-
└─────────────────┘ └────────────────────┘ └────────┬────────┘
|
139
|
-
│
|
140
|
-
▼
|
141
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
142
|
-
│ │ │ │ │ │
|
143
|
-
│ Result │◄─────┤ Error Handling │◄─────┤ Dispatcher │
|
144
|
-
│ │ │ │ │ (execution) │
|
145
|
-
└─────────────────┘ └────────────────────┘ └─────────────────┘
|
146
|
-
```
|
147
|
-
|
148
|
-
### API Documentation Generation
|
149
|
-
|
150
|
-
```
|
151
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
152
|
-
│ │ │ │ │ │
|
153
|
-
│ Command │ │ Schema Generator │ │ OpenAPI/ │
|
154
|
-
│ Metadata ├─────►│ ├─────►│ JSON Schema │
|
155
|
-
│ │ │ │ │ │
|
156
|
-
└─────────────────┘ └────────────────────┘ └────────┬────────┘
|
157
|
-
│
|
158
|
-
▼
|
159
|
-
┌─────────────────┐
|
160
|
-
│ │
|
161
|
-
│ API Docs UI │
|
162
|
-
│ (Swagger/ │
|
163
|
-
│ ReDoc) │
|
164
|
-
└─────────────────┘
|
165
|
-
```
|
166
|
-
|
167
|
-
## System Extension
|
168
|
-
|
169
|
-
### Creating a Custom Dispatcher
|
170
|
-
|
171
|
-
```python
|
172
|
-
from command_registry.dispatchers import BaseDispatcher
|
173
|
-
from typing import Dict, Any, List, Optional, Callable
|
174
|
-
|
175
|
-
class MyCustomDispatcher(BaseDispatcher):
|
176
|
-
def __init__(self):
|
177
|
-
self._commands = {}
|
178
|
-
self._info = {}
|
179
|
-
|
180
|
-
def register_handler(
|
181
|
-
self,
|
182
|
-
command_name: str,
|
183
|
-
handler: Callable,
|
184
|
-
description: str = None,
|
185
|
-
summary: str = None,
|
186
|
-
params: Dict[str, Any] = None
|
187
|
-
) -> None:
|
188
|
-
self._commands[command_name] = handler
|
189
|
-
self._info[command_name] = {
|
190
|
-
"description": description,
|
191
|
-
"summary": summary,
|
192
|
-
"params": params or {}
|
193
|
-
}
|
194
|
-
|
195
|
-
def execute(self, command_name: str, params: Dict[str, Any] = None) -> Any:
|
196
|
-
if command_name not in self._commands:
|
197
|
-
raise ValueError(f"Command '{command_name}' not found")
|
198
|
-
|
199
|
-
handler = self._commands[command_name]
|
200
|
-
return handler(**params or {})
|
201
|
-
|
202
|
-
def get_valid_commands(self) -> List[str]:
|
203
|
-
return list(self._commands.keys())
|
204
|
-
|
205
|
-
def get_command_info(self, command_name: str) -> Optional[Dict[str, Any]]:
|
206
|
-
return self._info.get(command_name)
|
207
|
-
|
208
|
-
def get_commands_info(self) -> Dict[str, Dict[str, Any]]:
|
209
|
-
return self._info
|
210
|
-
```
|
211
|
-
|
212
|
-
### Creating a Custom Protocol Adapter
|
213
|
-
|
214
|
-
```python
|
215
|
-
from command_registry import CommandRegistry
|
216
|
-
from typing import Dict, Any
|
217
|
-
|
218
|
-
class GraphQLAdapter:
|
219
|
-
def __init__(self, registry: CommandRegistry):
|
220
|
-
self.registry = registry
|
221
|
-
|
222
|
-
def generate_schema(self) -> str:
|
223
|
-
"""Generates GraphQL schema based on command metadata."""
|
224
|
-
commands_info = self.registry.get_all_commands_info()
|
225
|
-
schema_types = []
|
226
|
-
query_fields = []
|
227
|
-
|
228
|
-
for cmd_name, info in commands_info.items():
|
229
|
-
# Generate types for input and output data
|
230
|
-
input_type = self._generate_input_type(cmd_name, info["params"])
|
231
|
-
output_type = self._generate_output_type(cmd_name, info.get("returns"))
|
232
|
-
|
233
|
-
schema_types.extend([input_type, output_type])
|
234
|
-
|
235
|
-
# Add field to Query
|
236
|
-
query_fields.append(
|
237
|
-
f"{cmd_name}(input: {cmd_name}Input): {cmd_name}Output"
|
238
|
-
)
|
239
|
-
|
240
|
-
# Form final schema
|
241
|
-
schema = "\n".join(schema_types)
|
242
|
-
schema += f"\ntype Query {{\n {chr(10).join(query_fields)}\n}}"
|
243
|
-
|
244
|
-
return schema
|
245
|
-
|
246
|
-
def _generate_input_type(self, cmd_name: str, params: Dict[str, Any]) -> str:
|
247
|
-
fields = []
|
248
|
-
for name, param_info in params.items():
|
249
|
-
field_type = self._map_type(param_info.get("type", "String"))
|
250
|
-
required = "!" if param_info.get("required", False) else ""
|
251
|
-
```
|
docs/architecture_ru.md
DELETED
@@ -1,343 +0,0 @@
|
|
1
|
-
# Архитектура Command Registry
|
2
|
-
|
3
|
-
Данный документ описывает архитектуру системы Command Registry, ее ключевые компоненты, их взаимодействие и принципы расширения.
|
4
|
-
|
5
|
-
## Обзор архитектуры
|
6
|
-
|
7
|
-
Command Registry - это модульная система, построенная вокруг концепции централизованного хранения и управления командами. Архитектура обеспечивает гибкость, расширяемость и соблюдение принципов SOLID.
|
8
|
-
|
9
|
-
Ключевые возможности системы:
|
10
|
-
|
11
|
-
1. **Определение команд как Python-функций** с использованием типизации и докстрингов
|
12
|
-
2. **Извлечение метаданных** из сигнатур функций и их документации
|
13
|
-
3. **Регистрация команд** в центральном реестре
|
14
|
-
4. **Предоставление унифицированного интерфейса** для выполнения команд
|
15
|
-
5. **Генерация документации API** на основе метаданных команд
|
16
|
-
6. **Экспорт команд** через различные протоколы (REST, JSON-RPC, CLI и т.д.)
|
17
|
-
|
18
|
-
## Компоненты системы
|
19
|
-
|
20
|
-

|
21
|
-
|
22
|
-
### Основные компоненты:
|
23
|
-
|
24
|
-
1. **Command Definition** - Определение команды (функция Python с типизацией и докстрингами)
|
25
|
-
2. **Dispatcher Component** - Диспетчер команд, отвечающий за их регистрацию и выполнение
|
26
|
-
3. **Metadata Extractor** - Извлекатель метаданных из докстрингов и сигнатур функций
|
27
|
-
4. **Protocol Adapter** - Адаптер для экспорта команд через различные протоколы
|
28
|
-
|
29
|
-
### CommandRegistry
|
30
|
-
|
31
|
-
Центральный компонент системы, который:
|
32
|
-
|
33
|
-
- Инициализирует и конфигурирует диспетчеры
|
34
|
-
- Предоставляет интерфейс для регистрации команд
|
35
|
-
- Управляет метаданными команд
|
36
|
-
- Координирует взаимодействие между компонентами
|
37
|
-
|
38
|
-
## Жизненный цикл команды
|
39
|
-
|
40
|
-
### 1. Определение команды
|
41
|
-
|
42
|
-
```python
|
43
|
-
def calculate_total(
|
44
|
-
prices: List[float],
|
45
|
-
discount: float = 0.0,
|
46
|
-
tax_rate: float = 0.0
|
47
|
-
) -> float:
|
48
|
-
"""
|
49
|
-
Рассчитывает общую стоимость с учетом скидки и налога.
|
50
|
-
|
51
|
-
Args:
|
52
|
-
prices: Список цен товаров
|
53
|
-
discount: Скидка в процентах (0-100)
|
54
|
-
tax_rate: Налоговая ставка в процентах (0-100)
|
55
|
-
|
56
|
-
Returns:
|
57
|
-
Общая стоимость с учетом скидки и налога
|
58
|
-
"""
|
59
|
-
subtotal = sum(prices)
|
60
|
-
discounted = subtotal * (1 - discount / 100)
|
61
|
-
total = discounted * (1 + tax_rate / 100)
|
62
|
-
return round(total, 2)
|
63
|
-
```
|
64
|
-
|
65
|
-
### 2. Регистрация команды
|
66
|
-
|
67
|
-
```python
|
68
|
-
from command_registry import CommandRegistry
|
69
|
-
from command_registry.dispatchers import CommandDispatcher
|
70
|
-
|
71
|
-
# Создание реестра команд
|
72
|
-
registry = CommandRegistry(CommandDispatcher())
|
73
|
-
|
74
|
-
# Регистрация команды
|
75
|
-
registry.register_command("calculate_total", calculate_total)
|
76
|
-
```
|
77
|
-
|
78
|
-
### 3. Выполнение команды
|
79
|
-
|
80
|
-
```python
|
81
|
-
# Выполнение команды
|
82
|
-
result = registry.execute(
|
83
|
-
"calculate_total",
|
84
|
-
{
|
85
|
-
"prices": [10.0, 20.0, 30.0],
|
86
|
-
"discount": 10.0,
|
87
|
-
"tax_rate": 7.0
|
88
|
-
}
|
89
|
-
)
|
90
|
-
print(result) # 57.33
|
91
|
-
```
|
92
|
-
|
93
|
-
### 4. Экспорт через API
|
94
|
-
|
95
|
-
```python
|
96
|
-
from fastapi import FastAPI
|
97
|
-
from command_registry.adapters import RESTAdapter
|
98
|
-
|
99
|
-
app = FastAPI()
|
100
|
-
adapter = RESTAdapter(registry)
|
101
|
-
adapter.register_endpoints(app)
|
102
|
-
```
|
103
|
-
|
104
|
-
## Диаграммы потока данных
|
105
|
-
|
106
|
-
### Процесс регистрации команды
|
107
|
-
|
108
|
-
```
|
109
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
110
|
-
│ │ │ │ │ │
|
111
|
-
│ Python функция ├─────►│ Metadata Extractor ├─────►│ Метаданные │
|
112
|
-
│ │ │ │ │ │
|
113
|
-
└─────────────────┘ └────────────────────┘ └────────┬────────┘
|
114
|
-
│
|
115
|
-
▼
|
116
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
117
|
-
│ │ │ │ │ │
|
118
|
-
│ CommandRegistry│◄─────┤ Валидация данных │◄─────┤ Параметры │
|
119
|
-
│ │ │ │ │ │
|
120
|
-
└────────┬────────┘ └────────────────────┘ └─────────────────┘
|
121
|
-
│
|
122
|
-
▼
|
123
|
-
┌─────────────────┐
|
124
|
-
│ │
|
125
|
-
│ Dispatcher │
|
126
|
-
│ │
|
127
|
-
└─────────────────┘
|
128
|
-
```
|
129
|
-
|
130
|
-
### Процесс выполнения команды
|
131
|
-
|
132
|
-
```
|
133
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
134
|
-
│ │ │ │ │ │
|
135
|
-
│ Имя команды │ │ │ │ Валидация │
|
136
|
-
│ + параметры ├─────►│ CommandRegistry ├─────►│ параметров │
|
137
|
-
│ │ │ │ │ │
|
138
|
-
└─────────────────┘ └────────────────────┘ └────────┬────────┘
|
139
|
-
│
|
140
|
-
▼
|
141
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
142
|
-
│ │ │ │ │ │
|
143
|
-
│ Результат │◄─────┤ Обработка ошибок │◄─────┤ Dispatcher │
|
144
|
-
│ │ │ │ │ (выполнение) │
|
145
|
-
└─────────────────┘ └────────────────────┘ └─────────────────┘
|
146
|
-
```
|
147
|
-
|
148
|
-
### Генерация документации API
|
149
|
-
|
150
|
-
```
|
151
|
-
┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
152
|
-
│ │ │ │ │ │
|
153
|
-
│ Метаданные │ │ Schema Generator │ │ OpenAPI/ │
|
154
|
-
│ команд ├─────►│ ├─────►│ JSON Schema │
|
155
|
-
│ │ │ │ │ │
|
156
|
-
└─────────────────┘ └────────────────────┘ └────────┬────────┘
|
157
|
-
│
|
158
|
-
▼
|
159
|
-
┌─────────────────┐
|
160
|
-
│ │
|
161
|
-
│ API Docs UI │
|
162
|
-
│ (Swagger/ │
|
163
|
-
│ ReDoc) │
|
164
|
-
└─────────────────┘
|
165
|
-
```
|
166
|
-
|
167
|
-
## Расширение системы
|
168
|
-
|
169
|
-
### Создание собственного диспетчера
|
170
|
-
|
171
|
-
```python
|
172
|
-
from command_registry.dispatchers import BaseDispatcher
|
173
|
-
from typing import Dict, Any, List, Optional, Callable
|
174
|
-
|
175
|
-
class MyCustomDispatcher(BaseDispatcher):
|
176
|
-
def __init__(self):
|
177
|
-
self._commands = {}
|
178
|
-
self._info = {}
|
179
|
-
|
180
|
-
def register_handler(
|
181
|
-
self,
|
182
|
-
command_name: str,
|
183
|
-
handler: Callable,
|
184
|
-
description: str = None,
|
185
|
-
summary: str = None,
|
186
|
-
params: Dict[str, Any] = None
|
187
|
-
) -> None:
|
188
|
-
self._commands[command_name] = handler
|
189
|
-
self._info[command_name] = {
|
190
|
-
"description": description,
|
191
|
-
"summary": summary,
|
192
|
-
"params": params or {}
|
193
|
-
}
|
194
|
-
|
195
|
-
def execute(self, command_name: str, params: Dict[str, Any] = None) -> Any:
|
196
|
-
if command_name not in self._commands:
|
197
|
-
raise ValueError(f"Command '{command_name}' not found")
|
198
|
-
|
199
|
-
handler = self._commands[command_name]
|
200
|
-
return handler(**params or {})
|
201
|
-
|
202
|
-
def get_valid_commands(self) -> List[str]:
|
203
|
-
return list(self._commands.keys())
|
204
|
-
|
205
|
-
def get_command_info(self, command_name: str) -> Optional[Dict[str, Any]]:
|
206
|
-
return self._info.get(command_name)
|
207
|
-
|
208
|
-
def get_commands_info(self) -> Dict[str, Dict[str, Any]]:
|
209
|
-
return self._info
|
210
|
-
```
|
211
|
-
|
212
|
-
### Создание собственного адаптера протокола
|
213
|
-
|
214
|
-
```python
|
215
|
-
from command_registry import CommandRegistry
|
216
|
-
from typing import Dict, Any
|
217
|
-
|
218
|
-
class GraphQLAdapter:
|
219
|
-
def __init__(self, registry: CommandRegistry):
|
220
|
-
self.registry = registry
|
221
|
-
|
222
|
-
def generate_schema(self) -> str:
|
223
|
-
"""Генерирует GraphQL схему на основе метаданных команд."""
|
224
|
-
commands_info = self.registry.get_all_commands_info()
|
225
|
-
schema_types = []
|
226
|
-
query_fields = []
|
227
|
-
|
228
|
-
for cmd_name, info in commands_info.items():
|
229
|
-
# Генерация типов для входных и выходных данных
|
230
|
-
input_type = self._generate_input_type(cmd_name, info["params"])
|
231
|
-
output_type = self._generate_output_type(cmd_name, info.get("returns"))
|
232
|
-
|
233
|
-
schema_types.extend([input_type, output_type])
|
234
|
-
|
235
|
-
# Добавление поля в Query
|
236
|
-
query_fields.append(
|
237
|
-
f"{cmd_name}(input: {cmd_name}Input): {cmd_name}Output"
|
238
|
-
)
|
239
|
-
|
240
|
-
# Формирование итоговой схемы
|
241
|
-
schema = "\n".join(schema_types)
|
242
|
-
schema += f"\ntype Query {{\n {chr(10).join(query_fields)}\n}}"
|
243
|
-
|
244
|
-
return schema
|
245
|
-
|
246
|
-
def _generate_input_type(self, cmd_name: str, params: Dict[str, Any]) -> str:
|
247
|
-
fields = []
|
248
|
-
for name, param_info in params.items():
|
249
|
-
field_type = self._map_type(param_info.get("type", "String"))
|
250
|
-
required = "!" if param_info.get("required", False) else ""
|
251
|
-
fields.append(f" {name}: {field_type}{required}")
|
252
|
-
|
253
|
-
return f"input {cmd_name}Input {{\n{chr(10).join(fields)}\n}}"
|
254
|
-
|
255
|
-
def _generate_output_type(self, cmd_name: str, returns_info: Dict[str, Any]) -> str:
|
256
|
-
return_type = "String"
|
257
|
-
if returns_info:
|
258
|
-
return_type = self._map_type(returns_info.get("type", "String"))
|
259
|
-
|
260
|
-
return (
|
261
|
-
f"type {cmd_name}Output {{\n"
|
262
|
-
f" result: {return_type}\n"
|
263
|
-
f" error: String\n"
|
264
|
-
f"}}"
|
265
|
-
)
|
266
|
-
|
267
|
-
def _map_type(self, python_type: str) -> str:
|
268
|
-
"""Преобразует типы Python в типы GraphQL."""
|
269
|
-
type_mapping = {
|
270
|
-
"str": "String",
|
271
|
-
"int": "Int",
|
272
|
-
"float": "Float",
|
273
|
-
"bool": "Boolean",
|
274
|
-
"list": "List",
|
275
|
-
"dict": "JSON",
|
276
|
-
# Добавьте другие маппинги по необходимости
|
277
|
-
}
|
278
|
-
return type_mapping.get(python_type, "String")
|
279
|
-
```
|
280
|
-
|
281
|
-
## Лучшие практики
|
282
|
-
|
283
|
-
### Организация команд в модули
|
284
|
-
|
285
|
-
Рекомендуется группировать связанные команды в модули по их функциональности:
|
286
|
-
|
287
|
-
```
|
288
|
-
commands/
|
289
|
-
├── __init__.py
|
290
|
-
├── user_commands.py # Команды для работы с пользователями
|
291
|
-
├── product_commands.py # Команды для работы с товарами
|
292
|
-
└── order_commands.py # Команды для работы с заказами
|
293
|
-
```
|
294
|
-
|
295
|
-
### Регистрация команд
|
296
|
-
|
297
|
-
Автоматическая регистрация из модуля:
|
298
|
-
|
299
|
-
```python
|
300
|
-
registry.scan_module("myapp.commands")
|
301
|
-
```
|
302
|
-
|
303
|
-
Ручная регистрация отдельных функций:
|
304
|
-
|
305
|
-
```python
|
306
|
-
from myapp.commands.user_commands import create_user, update_user, delete_user
|
307
|
-
|
308
|
-
registry.register_command("create_user", create_user)
|
309
|
-
registry.register_command("update_user", update_user)
|
310
|
-
registry.register_command("delete_user", delete_user)
|
311
|
-
```
|
312
|
-
|
313
|
-
### Обработка ошибок
|
314
|
-
|
315
|
-
```python
|
316
|
-
def divide_numbers(a: float, b: float) -> float:
|
317
|
-
"""
|
318
|
-
Делит число a на число b.
|
319
|
-
|
320
|
-
Args:
|
321
|
-
a: Делимое
|
322
|
-
b: Делитель (не должен быть равен 0)
|
323
|
-
|
324
|
-
Returns:
|
325
|
-
Результат деления a на b
|
326
|
-
|
327
|
-
Raises:
|
328
|
-
ValueError: Если делитель равен 0
|
329
|
-
"""
|
330
|
-
if b == 0:
|
331
|
-
raise ValueError("Делитель не может быть равен 0")
|
332
|
-
return a / b
|
333
|
-
```
|
334
|
-
|
335
|
-
## Заключение
|
336
|
-
|
337
|
-
Архитектура Command Registry обеспечивает:
|
338
|
-
|
339
|
-
1. **Четкое разделение ответственности** между компонентами системы
|
340
|
-
2. **Расширяемость** через добавление новых диспетчеров и адаптеров
|
341
|
-
3. **Простоту использования** для разработчиков команд
|
342
|
-
4. **Автоматизацию** извлечения метаданных и валидации
|
343
|
-
5. **Интероперабельность** с различными протоколами и форматами
|