mcp-proxy-adapter 2.1.17__py3-none-any.whl → 3.0.1__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/__init__.py +19 -0
- examples/anti_patterns/README.md +51 -0
- examples/anti_patterns/__init__.py +9 -0
- examples/anti_patterns/bad_design/README.md +72 -0
- examples/anti_patterns/bad_design/global_state.py +170 -0
- examples/anti_patterns/bad_design/monolithic_command.py +272 -0
- examples/basic_example/README.md +245 -0
- examples/basic_example/__init__.py +8 -0
- examples/basic_example/commands/__init__.py +5 -0
- examples/basic_example/commands/echo_command.py +95 -0
- examples/basic_example/commands/math_command.py +151 -0
- examples/basic_example/commands/time_command.py +152 -0
- examples/basic_example/config.json +25 -0
- examples/basic_example/docs/EN/README.md +177 -0
- examples/basic_example/docs/RU/README.md +177 -0
- examples/basic_example/server.py +151 -0
- examples/basic_example/tests/conftest.py +243 -0
- examples/commands/echo_command.py +52 -0
- examples/commands/echo_result.py +65 -0
- examples/commands/get_date_command.py +98 -0
- examples/commands/new_uuid4_command.py +91 -0
- examples/complete_example/Dockerfile +24 -0
- examples/complete_example/README.md +92 -0
- examples/complete_example/__init__.py +8 -0
- examples/complete_example/commands/__init__.py +5 -0
- examples/complete_example/commands/system_command.py +328 -0
- examples/complete_example/config.json +41 -0
- examples/complete_example/configs/config.dev.yaml +40 -0
- examples/complete_example/configs/config.docker.yaml +40 -0
- examples/complete_example/docker-compose.yml +35 -0
- examples/complete_example/requirements.txt +20 -0
- examples/complete_example/server.py +139 -0
- examples/minimal_example/README.md +65 -0
- examples/minimal_example/__init__.py +8 -0
- examples/minimal_example/config.json +14 -0
- examples/minimal_example/main.py +136 -0
- examples/minimal_example/simple_server.py +163 -0
- examples/minimal_example/tests/conftest.py +171 -0
- examples/minimal_example/tests/test_hello_command.py +111 -0
- examples/minimal_example/tests/test_integration.py +181 -0
- examples/server.py +69 -0
- examples/simple_server.py +128 -0
- examples/test_server.py +134 -0
- examples/tool_description_example.py +82 -0
- mcp_proxy_adapter/__init__.py +33 -1
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +391 -0
- mcp_proxy_adapter/api/handlers.py +229 -0
- mcp_proxy_adapter/api/middleware/__init__.py +49 -0
- mcp_proxy_adapter/api/middleware/auth.py +146 -0
- mcp_proxy_adapter/api/middleware/base.py +79 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +198 -0
- mcp_proxy_adapter/api/middleware/logging.py +96 -0
- mcp_proxy_adapter/api/middleware/performance.py +83 -0
- mcp_proxy_adapter/api/middleware/rate_limit.py +152 -0
- mcp_proxy_adapter/api/schemas.py +305 -0
- mcp_proxy_adapter/api/tool_integration.py +223 -0
- mcp_proxy_adapter/api/tools.py +198 -0
- mcp_proxy_adapter/commands/__init__.py +19 -0
- mcp_proxy_adapter/commands/base.py +301 -0
- mcp_proxy_adapter/commands/command_registry.py +231 -0
- mcp_proxy_adapter/commands/config_command.py +113 -0
- mcp_proxy_adapter/commands/health_command.py +136 -0
- mcp_proxy_adapter/commands/help_command.py +193 -0
- mcp_proxy_adapter/commands/result.py +215 -0
- mcp_proxy_adapter/config.py +195 -0
- mcp_proxy_adapter/core/__init__.py +0 -0
- mcp_proxy_adapter/core/errors.py +173 -0
- mcp_proxy_adapter/core/logging.py +205 -0
- mcp_proxy_adapter/core/utils.py +138 -0
- mcp_proxy_adapter/custom_openapi.py +125 -0
- mcp_proxy_adapter/openapi.py +403 -0
- mcp_proxy_adapter/py.typed +0 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +3 -0
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +115 -0
- mcp_proxy_adapter/tests/api/test_middleware.py +336 -0
- mcp_proxy_adapter/tests/commands/__init__.py +3 -0
- mcp_proxy_adapter/tests/commands/test_config_command.py +211 -0
- mcp_proxy_adapter/tests/commands/test_echo_command.py +127 -0
- mcp_proxy_adapter/tests/commands/test_help_command.py +133 -0
- mcp_proxy_adapter/tests/conftest.py +131 -0
- mcp_proxy_adapter/tests/functional/__init__.py +3 -0
- mcp_proxy_adapter/tests/functional/test_api.py +235 -0
- mcp_proxy_adapter/tests/integration/__init__.py +3 -0
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +130 -0
- mcp_proxy_adapter/tests/integration/test_integration.py +255 -0
- mcp_proxy_adapter/tests/performance/__init__.py +3 -0
- mcp_proxy_adapter/tests/performance/test_performance.py +189 -0
- mcp_proxy_adapter/tests/stubs/__init__.py +10 -0
- mcp_proxy_adapter/tests/stubs/echo_command.py +104 -0
- mcp_proxy_adapter/tests/test_api_endpoints.py +271 -0
- mcp_proxy_adapter/tests/test_api_handlers.py +289 -0
- mcp_proxy_adapter/tests/test_base_command.py +123 -0
- mcp_proxy_adapter/tests/test_batch_requests.py +117 -0
- mcp_proxy_adapter/tests/test_command_registry.py +245 -0
- mcp_proxy_adapter/tests/test_config.py +127 -0
- mcp_proxy_adapter/tests/test_utils.py +65 -0
- mcp_proxy_adapter/tests/unit/__init__.py +3 -0
- mcp_proxy_adapter/tests/unit/test_base_command.py +130 -0
- mcp_proxy_adapter/tests/unit/test_config.py +217 -0
- mcp_proxy_adapter/version.py +3 -0
- mcp_proxy_adapter-3.0.1.dist-info/METADATA +200 -0
- mcp_proxy_adapter-3.0.1.dist-info/RECORD +109 -0
- {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/top_level.txt +1 -0
- mcp_proxy_adapter/adapter.py +0 -697
- mcp_proxy_adapter/analyzers/__init__.py +0 -1
- mcp_proxy_adapter/analyzers/docstring_analyzer.py +0 -199
- mcp_proxy_adapter/analyzers/type_analyzer.py +0 -151
- mcp_proxy_adapter/dispatchers/__init__.py +0 -1
- mcp_proxy_adapter/dispatchers/base_dispatcher.py +0 -85
- mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +0 -262
- mcp_proxy_adapter/examples/analyze_config.py +0 -141
- mcp_proxy_adapter/examples/basic_integration.py +0 -155
- mcp_proxy_adapter/examples/docstring_and_schema_example.py +0 -69
- mcp_proxy_adapter/examples/extension_example.py +0 -72
- mcp_proxy_adapter/examples/help_best_practices.py +0 -67
- mcp_proxy_adapter/examples/help_usage.py +0 -64
- mcp_proxy_adapter/examples/mcp_proxy_client.py +0 -131
- mcp_proxy_adapter/examples/openapi_server.py +0 -383
- mcp_proxy_adapter/examples/project_structure_example.py +0 -47
- mcp_proxy_adapter/examples/testing_example.py +0 -64
- mcp_proxy_adapter/models.py +0 -47
- mcp_proxy_adapter/registry.py +0 -439
- mcp_proxy_adapter/schema.py +0 -257
- mcp_proxy_adapter/testing_utils.py +0 -112
- mcp_proxy_adapter/validators/__init__.py +0 -1
- mcp_proxy_adapter/validators/docstring_validator.py +0 -75
- mcp_proxy_adapter/validators/metadata_validator.py +0 -76
- mcp_proxy_adapter-2.1.17.dist-info/METADATA +0 -376
- mcp_proxy_adapter-2.1.17.dist-info/RECORD +0 -30
- {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,215 @@
|
|
1
|
+
"""
|
2
|
+
Module with base classes for command results.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import json
|
6
|
+
from abc import ABC, abstractmethod
|
7
|
+
from typing import Any, Dict, List, Optional, Type, TypeVar, Union
|
8
|
+
|
9
|
+
T = TypeVar("T", bound="CommandResult")
|
10
|
+
|
11
|
+
|
12
|
+
class CommandResult(ABC):
|
13
|
+
"""
|
14
|
+
Base abstract class for command execution results.
|
15
|
+
"""
|
16
|
+
|
17
|
+
@abstractmethod
|
18
|
+
def to_dict(self) -> Dict[str, Any]:
|
19
|
+
"""
|
20
|
+
Converts result to dictionary for serialization.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
Dictionary with result data.
|
24
|
+
"""
|
25
|
+
pass
|
26
|
+
|
27
|
+
@classmethod
|
28
|
+
@abstractmethod
|
29
|
+
def get_schema(cls) -> Dict[str, Any]:
|
30
|
+
"""
|
31
|
+
Returns JSON schema for result validation.
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
Dictionary with JSON schema.
|
35
|
+
"""
|
36
|
+
pass
|
37
|
+
|
38
|
+
def to_json(self, indent: Optional[int] = None) -> str:
|
39
|
+
"""
|
40
|
+
Converts result to JSON string.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
indent: Indentation for JSON formatting.
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
JSON string with result.
|
47
|
+
"""
|
48
|
+
return json.dumps(self.to_dict(), ensure_ascii=False, indent=indent)
|
49
|
+
|
50
|
+
@classmethod
|
51
|
+
def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
|
52
|
+
"""
|
53
|
+
Creates result instance from dictionary.
|
54
|
+
This method must be overridden in subclasses.
|
55
|
+
|
56
|
+
Args:
|
57
|
+
data: Dictionary with result data.
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
Result instance.
|
61
|
+
"""
|
62
|
+
raise NotImplementedError("Method from_dict must be implemented in subclasses")
|
63
|
+
|
64
|
+
|
65
|
+
class SuccessResult(CommandResult):
|
66
|
+
"""
|
67
|
+
Base class for successful command results.
|
68
|
+
"""
|
69
|
+
|
70
|
+
def __init__(self, data: Optional[Dict[str, Any]] = None, message: Optional[str] = None):
|
71
|
+
"""
|
72
|
+
Initialize successful result.
|
73
|
+
|
74
|
+
Args:
|
75
|
+
data: Result data.
|
76
|
+
message: Result message.
|
77
|
+
"""
|
78
|
+
self.data = data or {}
|
79
|
+
self.message = message
|
80
|
+
|
81
|
+
def to_dict(self) -> Dict[str, Any]:
|
82
|
+
"""
|
83
|
+
Converts result to dictionary for serialization.
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
Dictionary with result data.
|
87
|
+
"""
|
88
|
+
result = {"success": True}
|
89
|
+
if self.data:
|
90
|
+
result["data"] = self.data
|
91
|
+
if self.message:
|
92
|
+
result["message"] = self.message
|
93
|
+
return result
|
94
|
+
|
95
|
+
@classmethod
|
96
|
+
def get_schema(cls) -> Dict[str, Any]:
|
97
|
+
"""
|
98
|
+
Returns JSON schema for result validation.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
Dictionary with JSON schema.
|
102
|
+
"""
|
103
|
+
return {
|
104
|
+
"type": "object",
|
105
|
+
"properties": {
|
106
|
+
"success": {"type": "boolean"},
|
107
|
+
"data": {"type": "object"},
|
108
|
+
"message": {"type": "string"}
|
109
|
+
},
|
110
|
+
"required": ["success"]
|
111
|
+
}
|
112
|
+
|
113
|
+
@classmethod
|
114
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SuccessResult":
|
115
|
+
"""
|
116
|
+
Creates successful result instance from dictionary.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
data: Dictionary with result data.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
Successful result instance.
|
123
|
+
"""
|
124
|
+
return cls(
|
125
|
+
data=data.get("data"),
|
126
|
+
message=data.get("message")
|
127
|
+
)
|
128
|
+
|
129
|
+
|
130
|
+
class ErrorResult(CommandResult):
|
131
|
+
"""
|
132
|
+
Base class for command results with error.
|
133
|
+
|
134
|
+
This class follows the JSON-RPC 2.0 error object format:
|
135
|
+
https://www.jsonrpc.org/specification#error_object
|
136
|
+
"""
|
137
|
+
|
138
|
+
def __init__(
|
139
|
+
self,
|
140
|
+
message: str,
|
141
|
+
code: int = -32000,
|
142
|
+
details: Optional[Dict[str, Any]] = None
|
143
|
+
):
|
144
|
+
"""
|
145
|
+
Initialize error result.
|
146
|
+
|
147
|
+
Args:
|
148
|
+
message: Error message.
|
149
|
+
code: Error code (following JSON-RPC 2.0 spec).
|
150
|
+
details: Additional error details.
|
151
|
+
"""
|
152
|
+
self.message = message
|
153
|
+
self.code = code
|
154
|
+
self.details = details or {}
|
155
|
+
|
156
|
+
def to_dict(self) -> Dict[str, Any]:
|
157
|
+
"""
|
158
|
+
Converts result to dictionary for serialization.
|
159
|
+
|
160
|
+
Returns:
|
161
|
+
Dictionary with result data in JSON-RPC 2.0 error format.
|
162
|
+
"""
|
163
|
+
result = {
|
164
|
+
"success": False,
|
165
|
+
"error": {
|
166
|
+
"code": self.code,
|
167
|
+
"message": self.message
|
168
|
+
}
|
169
|
+
}
|
170
|
+
if self.details:
|
171
|
+
result["error"]["data"] = self.details
|
172
|
+
return result
|
173
|
+
|
174
|
+
@classmethod
|
175
|
+
def get_schema(cls) -> Dict[str, Any]:
|
176
|
+
"""
|
177
|
+
Returns JSON schema for result validation.
|
178
|
+
|
179
|
+
Returns:
|
180
|
+
Dictionary with JSON schema.
|
181
|
+
"""
|
182
|
+
return {
|
183
|
+
"type": "object",
|
184
|
+
"properties": {
|
185
|
+
"success": {"type": "boolean"},
|
186
|
+
"error": {
|
187
|
+
"type": "object",
|
188
|
+
"properties": {
|
189
|
+
"code": {"type": "integer"},
|
190
|
+
"message": {"type": "string"},
|
191
|
+
"data": {"type": "object"}
|
192
|
+
},
|
193
|
+
"required": ["code", "message"]
|
194
|
+
}
|
195
|
+
},
|
196
|
+
"required": ["success", "error"]
|
197
|
+
}
|
198
|
+
|
199
|
+
@classmethod
|
200
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ErrorResult":
|
201
|
+
"""
|
202
|
+
Creates error result instance from dictionary.
|
203
|
+
|
204
|
+
Args:
|
205
|
+
data: Dictionary with result data.
|
206
|
+
|
207
|
+
Returns:
|
208
|
+
Error result instance.
|
209
|
+
"""
|
210
|
+
error = data.get("error", {})
|
211
|
+
return cls(
|
212
|
+
message=error.get("message", "Unknown error"),
|
213
|
+
code=error.get("code", -32000),
|
214
|
+
details=error.get("data")
|
215
|
+
)
|
@@ -0,0 +1,195 @@
|
|
1
|
+
"""
|
2
|
+
Module for microservice configuration management.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import json
|
6
|
+
import os
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import Any, Dict, Optional
|
9
|
+
|
10
|
+
|
11
|
+
class Config:
|
12
|
+
"""
|
13
|
+
Configuration management class for the microservice.
|
14
|
+
Allows loading settings from configuration file and environment variables.
|
15
|
+
"""
|
16
|
+
|
17
|
+
def __init__(self, config_path: Optional[str] = None):
|
18
|
+
"""
|
19
|
+
Initialize configuration.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
config_path: Path to configuration file. If not specified, "./config.json" is used.
|
23
|
+
"""
|
24
|
+
self.config_path = config_path or "./config.json"
|
25
|
+
self.config_data: Dict[str, Any] = {}
|
26
|
+
self.load_config()
|
27
|
+
|
28
|
+
def load_config(self) -> None:
|
29
|
+
"""
|
30
|
+
Load configuration from file and environment variables.
|
31
|
+
"""
|
32
|
+
# Set default config values
|
33
|
+
self.config_data = {
|
34
|
+
"server": {
|
35
|
+
"host": "0.0.0.0",
|
36
|
+
"port": 8000,
|
37
|
+
"debug": False,
|
38
|
+
"log_level": "INFO"
|
39
|
+
},
|
40
|
+
"logging": {
|
41
|
+
"level": "INFO",
|
42
|
+
"file": None
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
# Try to load configuration from file
|
47
|
+
if os.path.exists(self.config_path):
|
48
|
+
try:
|
49
|
+
with open(self.config_path, 'r', encoding='utf-8') as f:
|
50
|
+
file_config = json.load(f)
|
51
|
+
self._update_nested_dict(self.config_data, file_config)
|
52
|
+
except Exception as e:
|
53
|
+
print(f"Error loading config from {self.config_path}: {e}")
|
54
|
+
|
55
|
+
# Load configuration from environment variables
|
56
|
+
self._load_env_variables()
|
57
|
+
|
58
|
+
def load_from_file(self, config_path: str) -> None:
|
59
|
+
"""
|
60
|
+
Load configuration from the specified file.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
config_path: Path to configuration file.
|
64
|
+
"""
|
65
|
+
self.config_path = config_path
|
66
|
+
self.load_config()
|
67
|
+
|
68
|
+
def _load_env_variables(self) -> None:
|
69
|
+
"""
|
70
|
+
Load configuration from environment variables.
|
71
|
+
Environment variables should be in format SERVICE_SECTION_KEY=value.
|
72
|
+
For example, SERVICE_SERVER_PORT=8080.
|
73
|
+
"""
|
74
|
+
prefix = "SERVICE_"
|
75
|
+
for key, value in os.environ.items():
|
76
|
+
if key.startswith(prefix):
|
77
|
+
parts = key[len(prefix):].lower().split("_", 1)
|
78
|
+
if len(parts) == 2:
|
79
|
+
section, param = parts
|
80
|
+
if section not in self.config_data:
|
81
|
+
self.config_data[section] = {}
|
82
|
+
self.config_data[section][param] = self._convert_env_value(value)
|
83
|
+
|
84
|
+
def _convert_env_value(self, value: str) -> Any:
|
85
|
+
"""
|
86
|
+
Convert environment variable value to appropriate type.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
value: Value as string
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Converted value
|
93
|
+
"""
|
94
|
+
# Try to convert to appropriate type
|
95
|
+
if value.lower() == "true":
|
96
|
+
return True
|
97
|
+
elif value.lower() == "false":
|
98
|
+
return False
|
99
|
+
elif value.isdigit():
|
100
|
+
return int(value)
|
101
|
+
else:
|
102
|
+
try:
|
103
|
+
return float(value)
|
104
|
+
except ValueError:
|
105
|
+
return value
|
106
|
+
|
107
|
+
def get(self, key: str, default: Any = None) -> Any:
|
108
|
+
"""
|
109
|
+
Get configuration value for key.
|
110
|
+
|
111
|
+
Args:
|
112
|
+
key: Configuration key in format "section.param"
|
113
|
+
default: Default value if key not found
|
114
|
+
|
115
|
+
Returns:
|
116
|
+
Configuration value
|
117
|
+
"""
|
118
|
+
parts = key.split(".")
|
119
|
+
|
120
|
+
# Get value from config
|
121
|
+
value = self.config_data
|
122
|
+
for part in parts:
|
123
|
+
if not isinstance(value, dict) or part not in value:
|
124
|
+
return default
|
125
|
+
value = value[part]
|
126
|
+
|
127
|
+
return value
|
128
|
+
|
129
|
+
def get_all(self) -> Dict[str, Any]:
|
130
|
+
"""
|
131
|
+
Get all configuration values.
|
132
|
+
|
133
|
+
Returns:
|
134
|
+
Dictionary with all configuration values
|
135
|
+
"""
|
136
|
+
return self.config_data.copy()
|
137
|
+
|
138
|
+
def set(self, key: str, value: Any) -> None:
|
139
|
+
"""
|
140
|
+
Set configuration value for key.
|
141
|
+
|
142
|
+
Args:
|
143
|
+
key: Configuration key in format "section.param"
|
144
|
+
value: Configuration value
|
145
|
+
"""
|
146
|
+
parts = key.split(".")
|
147
|
+
if len(parts) == 1:
|
148
|
+
self.config_data[key] = value
|
149
|
+
else:
|
150
|
+
section = parts[0]
|
151
|
+
param = ".".join(parts[1:])
|
152
|
+
|
153
|
+
if section not in self.config_data:
|
154
|
+
self.config_data[section] = {}
|
155
|
+
|
156
|
+
current = self.config_data[section]
|
157
|
+
for part in parts[1:-1]:
|
158
|
+
if part not in current:
|
159
|
+
current[part] = {}
|
160
|
+
current = current[part]
|
161
|
+
|
162
|
+
current[parts[-1]] = value
|
163
|
+
|
164
|
+
def save(self, path: Optional[str] = None) -> None:
|
165
|
+
"""
|
166
|
+
Save configuration to file.
|
167
|
+
|
168
|
+
Args:
|
169
|
+
path: Path to configuration file. If not specified, self.config_path is used.
|
170
|
+
"""
|
171
|
+
save_path = path or self.config_path
|
172
|
+
with open(save_path, 'w', encoding='utf-8') as f:
|
173
|
+
json.dump(self.config_data, f, indent=2)
|
174
|
+
|
175
|
+
def _update_nested_dict(self, d: Dict, u: Dict) -> Dict:
|
176
|
+
"""
|
177
|
+
Update nested dictionary recursively.
|
178
|
+
|
179
|
+
Args:
|
180
|
+
d: Dictionary to update
|
181
|
+
u: Dictionary with new values
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
Updated dictionary
|
185
|
+
"""
|
186
|
+
for k, v in u.items():
|
187
|
+
if isinstance(v, dict) and k in d and isinstance(d[k], dict):
|
188
|
+
self._update_nested_dict(d[k], v)
|
189
|
+
else:
|
190
|
+
d[k] = v
|
191
|
+
return d
|
192
|
+
|
193
|
+
|
194
|
+
# Singleton instance
|
195
|
+
config = Config()
|
File without changes
|
@@ -0,0 +1,173 @@
|
|
1
|
+
"""
|
2
|
+
Module for defining errors and exceptions for the microservice.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
6
|
+
|
7
|
+
|
8
|
+
class MicroserviceError(Exception):
|
9
|
+
"""
|
10
|
+
Base class for all microservice exceptions.
|
11
|
+
|
12
|
+
Attributes:
|
13
|
+
message: Error message.
|
14
|
+
code: Error code.
|
15
|
+
data: Additional error data.
|
16
|
+
"""
|
17
|
+
def __init__(self, message: str, code: int = -32000, data: Optional[Dict[str, Any]] = None):
|
18
|
+
"""
|
19
|
+
Initialize the error.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
message: Error message.
|
23
|
+
code: Error code according to JSON-RPC standard.
|
24
|
+
data: Additional error data.
|
25
|
+
"""
|
26
|
+
self.message = message
|
27
|
+
self.code = code
|
28
|
+
self.data = data or {}
|
29
|
+
super().__init__(message)
|
30
|
+
|
31
|
+
def to_dict(self) -> Dict[str, Any]:
|
32
|
+
"""
|
33
|
+
Converts the error to a dictionary for JSON-RPC response.
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
Dictionary with error information.
|
37
|
+
"""
|
38
|
+
result = {
|
39
|
+
"code": self.code,
|
40
|
+
"message": self.message
|
41
|
+
}
|
42
|
+
|
43
|
+
if self.data:
|
44
|
+
result["data"] = self.data
|
45
|
+
|
46
|
+
return result
|
47
|
+
|
48
|
+
|
49
|
+
class ParseError(MicroserviceError):
|
50
|
+
"""
|
51
|
+
Error while parsing JSON request.
|
52
|
+
JSON-RPC Error code: -32700
|
53
|
+
"""
|
54
|
+
def __init__(self, message: str = "Parse error", data: Optional[Dict[str, Any]] = None):
|
55
|
+
super().__init__(message, code=-32700, data=data)
|
56
|
+
|
57
|
+
|
58
|
+
class InvalidRequestError(MicroserviceError):
|
59
|
+
"""
|
60
|
+
Invalid JSON-RPC request format.
|
61
|
+
JSON-RPC Error code: -32600
|
62
|
+
"""
|
63
|
+
def __init__(self, message: str = "Invalid Request", data: Optional[Dict[str, Any]] = None):
|
64
|
+
super().__init__(message, code=-32600, data=data)
|
65
|
+
|
66
|
+
|
67
|
+
class MethodNotFoundError(MicroserviceError):
|
68
|
+
"""
|
69
|
+
Method not found error.
|
70
|
+
JSON-RPC Error code: -32601
|
71
|
+
"""
|
72
|
+
def __init__(self, message: str = "Method not found", data: Optional[Dict[str, Any]] = None):
|
73
|
+
super().__init__(message, code=-32601, data=data)
|
74
|
+
|
75
|
+
|
76
|
+
class InvalidParamsError(MicroserviceError):
|
77
|
+
"""
|
78
|
+
Invalid method parameters.
|
79
|
+
JSON-RPC Error code: -32602
|
80
|
+
"""
|
81
|
+
def __init__(self, message: str = "Invalid params", data: Optional[Dict[str, Any]] = None):
|
82
|
+
super().__init__(message, code=-32602, data=data)
|
83
|
+
|
84
|
+
|
85
|
+
class InternalError(MicroserviceError):
|
86
|
+
"""
|
87
|
+
Internal server error.
|
88
|
+
JSON-RPC Error code: -32603
|
89
|
+
"""
|
90
|
+
def __init__(self, message: str = "Internal error", data: Optional[Dict[str, Any]] = None):
|
91
|
+
super().__init__(message, code=-32603, data=data)
|
92
|
+
|
93
|
+
|
94
|
+
class ValidationError(MicroserviceError):
|
95
|
+
"""
|
96
|
+
Input data validation error.
|
97
|
+
JSON-RPC Error code: -32602 (using Invalid params code)
|
98
|
+
"""
|
99
|
+
def __init__(self, message: str = "Validation error", data: Optional[Dict[str, Any]] = None):
|
100
|
+
super().__init__(message, code=-32602, data=data)
|
101
|
+
|
102
|
+
|
103
|
+
class CommandError(MicroserviceError):
|
104
|
+
"""
|
105
|
+
Command execution error.
|
106
|
+
JSON-RPC Error code: -32000 (server error)
|
107
|
+
"""
|
108
|
+
def __init__(self, message: str = "Command execution error", data: Optional[Dict[str, Any]] = None):
|
109
|
+
super().__init__(message, code=-32000, data=data)
|
110
|
+
|
111
|
+
|
112
|
+
class NotFoundError(MicroserviceError):
|
113
|
+
"""
|
114
|
+
"Not found" error.
|
115
|
+
JSON-RPC Error code: -32601 (using Method not found code)
|
116
|
+
"""
|
117
|
+
def __init__(self, message: str = "Resource not found", data: Optional[Dict[str, Any]] = None):
|
118
|
+
super().__init__(message, code=-32601, data=data)
|
119
|
+
|
120
|
+
|
121
|
+
class ConfigurationError(MicroserviceError):
|
122
|
+
"""
|
123
|
+
Configuration error.
|
124
|
+
JSON-RPC Error code: -32603 (using Internal error code)
|
125
|
+
"""
|
126
|
+
def __init__(self, message: str = "Configuration error", data: Optional[Dict[str, Any]] = None):
|
127
|
+
super().__init__(message, code=-32603, data=data)
|
128
|
+
|
129
|
+
|
130
|
+
class AuthenticationError(MicroserviceError):
|
131
|
+
"""
|
132
|
+
Authentication error.
|
133
|
+
JSON-RPC Error code: -32001 (server error)
|
134
|
+
"""
|
135
|
+
def __init__(self, message: str = "Authentication error", data: Optional[Dict[str, Any]] = None):
|
136
|
+
super().__init__(message, code=-32001, data=data)
|
137
|
+
|
138
|
+
|
139
|
+
class AuthorizationError(MicroserviceError):
|
140
|
+
"""
|
141
|
+
Authorization error.
|
142
|
+
JSON-RPC Error code: -32002 (server error)
|
143
|
+
"""
|
144
|
+
def __init__(self, message: str = "Authorization error", data: Optional[Dict[str, Any]] = None):
|
145
|
+
super().__init__(message, code=-32002, data=data)
|
146
|
+
|
147
|
+
|
148
|
+
class TimeoutError(MicroserviceError):
|
149
|
+
"""
|
150
|
+
Timeout error.
|
151
|
+
JSON-RPC Error code: -32003 (server error)
|
152
|
+
"""
|
153
|
+
def __init__(self, message: str = "Timeout error", data: Optional[Dict[str, Any]] = None):
|
154
|
+
super().__init__(message, code=-32003, data=data)
|
155
|
+
|
156
|
+
|
157
|
+
def format_validation_errors(errors: List[Dict[str, Any]]) -> Dict[str, Any]:
|
158
|
+
"""
|
159
|
+
Formats validation errors into a standard format.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
errors: List of validation errors.
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
Formatted validation errors.
|
166
|
+
"""
|
167
|
+
formatted_errors = {}
|
168
|
+
for error in errors:
|
169
|
+
loc = error.get("loc", [])
|
170
|
+
field = ".".join(str(item) for item in loc)
|
171
|
+
msg = error.get("msg", "Validation error")
|
172
|
+
formatted_errors[field] = msg
|
173
|
+
return formatted_errors
|