pygeai 0.6.0b13__py3-none-any.whl → 0.6.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.
- pygeai/__init__.py +1 -2
- pygeai/_docs/source/content/api_reference/project.rst +392 -0
- pygeai/_docs/source/content/authentication.rst +130 -1
- pygeai/_docs/source/content/debugger.rst +327 -157
- pygeai/_docs/source/content/migration.rst +391 -7
- pygeai/_docs/source/pygeai.core.common.rst +8 -0
- pygeai/_docs/source/pygeai.tests.auth.rst +56 -0
- pygeai/_docs/source/pygeai.tests.cli.rst +8 -0
- pygeai/admin/clients.py +1 -3
- pygeai/analytics/clients.py +1 -1
- pygeai/assistant/clients.py +2 -7
- pygeai/assistant/data/clients.py +0 -8
- pygeai/assistant/data_analyst/clients.py +0 -2
- pygeai/assistant/managers.py +1 -1
- pygeai/assistant/rag/clients.py +0 -2
- pygeai/assistant/rag/mappers.py +9 -11
- pygeai/auth/clients.py +26 -7
- pygeai/auth/endpoints.py +2 -1
- pygeai/chat/clients.py +2 -2
- pygeai/chat/managers.py +1 -1
- pygeai/cli/commands/admin.py +13 -25
- pygeai/cli/commands/analytics.py +56 -88
- pygeai/cli/commands/assistant.py +84 -138
- pygeai/cli/commands/auth.py +23 -46
- pygeai/cli/commands/base.py +0 -1
- pygeai/cli/commands/chat.py +218 -209
- pygeai/cli/commands/common.py +5 -5
- pygeai/cli/commands/configuration.py +79 -29
- pygeai/cli/commands/docs.py +3 -4
- pygeai/cli/commands/embeddings.py +13 -19
- pygeai/cli/commands/evaluation.py +133 -344
- pygeai/cli/commands/feedback.py +7 -15
- pygeai/cli/commands/files.py +26 -53
- pygeai/cli/commands/gam.py +28 -69
- pygeai/cli/commands/lab/ai_lab.py +96 -142
- pygeai/cli/commands/lab/common.py +1 -1
- pygeai/cli/commands/lab/spec.py +12 -32
- pygeai/cli/commands/llm.py +9 -18
- pygeai/cli/commands/migrate.py +43 -99
- pygeai/cli/commands/organization.py +223 -196
- pygeai/cli/commands/rag.py +35 -58
- pygeai/cli/commands/rerank.py +21 -25
- pygeai/cli/commands/secrets.py +39 -67
- pygeai/cli/commands/usage_limits.py +50 -136
- pygeai/cli/commands/validators.py +1 -1
- pygeai/cli/geai.py +32 -3
- pygeai/cli/geai_proxy.py +6 -2
- pygeai/cli/install_man.py +1 -1
- pygeai/cli/parsers.py +1 -1
- pygeai/core/base/clients.py +90 -21
- pygeai/core/base/mappers.py +39 -55
- pygeai/core/base/session.py +134 -22
- pygeai/core/common/config.py +50 -13
- pygeai/core/common/constants.py +8 -0
- pygeai/core/common/exceptions.py +6 -0
- pygeai/core/embeddings/clients.py +0 -1
- pygeai/core/embeddings/managers.py +0 -1
- pygeai/core/feedback/clients.py +0 -2
- pygeai/core/feedback/models.py +1 -1
- pygeai/core/files/clients.py +0 -3
- pygeai/core/files/managers.py +1 -1
- pygeai/core/files/mappers.py +4 -5
- pygeai/core/llm/clients.py +0 -1
- pygeai/core/models.py +4 -4
- pygeai/core/plugins/clients.py +0 -3
- pygeai/core/plugins/models.py +2 -2
- pygeai/core/rerank/clients.py +0 -2
- pygeai/core/secrets/clients.py +0 -2
- pygeai/core/services/rest.py +80 -14
- pygeai/core/singleton.py +24 -0
- pygeai/dbg/__init__.py +2 -2
- pygeai/dbg/debugger.py +276 -38
- pygeai/evaluation/clients.py +2 -4
- pygeai/evaluation/dataset/clients.py +0 -1
- pygeai/evaluation/plan/clients.py +0 -2
- pygeai/evaluation/result/clients.py +0 -2
- pygeai/gam/clients.py +1 -3
- pygeai/health/clients.py +1 -3
- pygeai/lab/clients.py +0 -1
- pygeai/lab/managers.py +0 -1
- pygeai/lab/models.py +0 -1
- pygeai/lab/strategies/clients.py +1 -2
- pygeai/lab/tools/clients.py +2 -2
- pygeai/lab/tools/mappers.py +1 -1
- pygeai/migration/strategies.py +5 -6
- pygeai/migration/tools.py +1 -1
- pygeai/organization/clients.py +118 -12
- pygeai/organization/endpoints.py +1 -0
- pygeai/organization/limits/clients.py +4 -6
- pygeai/organization/limits/managers.py +1 -4
- pygeai/organization/managers.py +2 -2
- pygeai/proxy/config.py +1 -0
- pygeai/proxy/managers.py +6 -5
- pygeai/tests/admin/test_clients.py +11 -11
- pygeai/tests/assistants/rag/test_clients.py +1 -1
- pygeai/tests/assistants/rag/test_models.py +1 -2
- pygeai/tests/assistants/test_clients.py +1 -1
- pygeai/tests/assistants/test_managers.py +1 -3
- pygeai/tests/auth/test_cli_configuration.py +252 -0
- pygeai/tests/auth/test_client_initialization.py +411 -0
- pygeai/tests/auth/test_clients.py +29 -27
- pygeai/tests/auth/test_config_manager.py +305 -0
- pygeai/tests/auth/test_header_injection.py +294 -0
- pygeai/tests/auth/test_oauth.py +3 -1
- pygeai/tests/auth/test_session_logging.py +119 -0
- pygeai/tests/auth/test_session_validation.py +408 -0
- pygeai/tests/auth/test_singleton_reset.py +201 -0
- pygeai/tests/chat/test_clients.py +1 -1
- pygeai/tests/chat/test_iris.py +1 -1
- pygeai/tests/chat/test_ui.py +0 -2
- pygeai/tests/cli/commands/lab/test_ai_lab.py +1 -3
- pygeai/tests/cli/commands/lab/test_common.py +0 -1
- pygeai/tests/cli/commands/test_chat.py +1 -1
- pygeai/tests/cli/commands/test_common.py +0 -1
- pygeai/tests/cli/commands/test_embeddings.py +2 -2
- pygeai/tests/cli/commands/test_evaluation.py +1 -9
- pygeai/tests/cli/commands/test_llm.py +1 -1
- pygeai/tests/cli/commands/test_migrate.py +1 -1
- pygeai/tests/cli/commands/test_rerank.py +0 -1
- pygeai/tests/cli/commands/test_secrets.py +1 -1
- pygeai/tests/cli/commands/test_show_help.py +0 -1
- pygeai/tests/cli/commands/test_validators.py +0 -1
- pygeai/tests/cli/test_credentials_flag.py +312 -0
- pygeai/tests/cli/test_error_handler.py +0 -1
- pygeai/tests/core/base/test_mappers.py +2 -2
- pygeai/tests/core/base/test_models.py +4 -4
- pygeai/tests/core/common/test_config.py +2 -7
- pygeai/tests/core/common/test_decorators.py +0 -1
- pygeai/tests/core/embeddings/test_managers.py +1 -1
- pygeai/tests/core/feedback/test_clients.py +2 -2
- pygeai/tests/core/files/test_clients.py +6 -6
- pygeai/tests/core/files/test_models.py +0 -1
- pygeai/tests/core/files/test_responses.py +0 -1
- pygeai/tests/core/llm/test_clients.py +1 -1
- pygeai/tests/core/plugins/test_clients.py +4 -4
- pygeai/tests/core/rerank/test_mappers.py +1 -3
- pygeai/tests/core/secrets/test_clients.py +2 -3
- pygeai/tests/core/services/test_rest.py +10 -10
- pygeai/tests/core/utils/test_console.py +0 -1
- pygeai/tests/dbg/test_debugger.py +95 -8
- pygeai/tests/evaluation/dataset/test_clients.py +24 -27
- pygeai/tests/evaluation/plan/test_clients.py +16 -18
- pygeai/tests/evaluation/result/test_clients.py +4 -5
- pygeai/tests/health/test_clients.py +2 -2
- pygeai/tests/integration/lab/agents/test_create_agent.py +1 -3
- pygeai/tests/integration/lab/agents/test_get_agent.py +1 -1
- pygeai/tests/integration/lab/processes/test_create_process.py +2 -2
- pygeai/tests/integration/lab/processes/test_create_task.py +2 -3
- pygeai/tests/integration/lab/processes/test_delete_process.py +0 -1
- pygeai/tests/integration/lab/processes/test_get_process.py +2 -4
- pygeai/tests/integration/lab/processes/test_list_process_instances.py +1 -3
- pygeai/tests/integration/lab/processes/test_update_process.py +3 -9
- pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +1 -2
- pygeai/tests/integration/lab/tools/test_delete_tool.py +1 -1
- pygeai/tests/integration/lab/tools/test_list_tools.py +1 -1
- pygeai/tests/integration/lab/tools/test_update_tool.py +1 -1
- pygeai/tests/lab/agents/test_clients.py +17 -17
- pygeai/tests/lab/processes/test_clients.py +67 -67
- pygeai/tests/lab/processes/test_mappers.py +23 -23
- pygeai/tests/lab/spec/test_loader.py +0 -2
- pygeai/tests/lab/spec/test_parsers.py +1 -2
- pygeai/tests/lab/strategies/test_clients.py +10 -10
- pygeai/tests/lab/test_managers.py +3 -5
- pygeai/tests/lab/test_mappers.py +1 -4
- pygeai/tests/lab/tools/test_clients.py +21 -21
- pygeai/tests/lab/tools/test_mappers.py +0 -1
- pygeai/tests/organization/limits/test_clients.py +33 -33
- pygeai/tests/organization/limits/test_managers.py +7 -7
- pygeai/tests/organization/test_clients.py +78 -60
- pygeai/tests/proxy/test_clients.py +1 -1
- pygeai/tests/proxy/test_integration.py +1 -4
- pygeai/tests/proxy/test_managers.py +1 -2
- pygeai/tests/proxy/test_servers.py +1 -2
- pygeai/tests/snippets/assistants/rag/delete_rag_assistant.py +0 -1
- pygeai/tests/snippets/assistants/rag/get_documents.py +0 -1
- pygeai/tests/snippets/assistants/rag/get_rag_assistant_data.py +0 -1
- pygeai/tests/snippets/chat/get_request_status.py +0 -1
- pygeai/tests/snippets/dbg/file_debugging.py +72 -0
- pygeai/tests/snippets/dbg/module_debugging.py +60 -0
- pygeai/tests/snippets/embeddings/cohere_example.py +2 -2
- pygeai/tests/snippets/embeddings/openai_base64_example.py +1 -1
- pygeai/tests/snippets/evaluation/dataset/complete_workflow_example.py +8 -8
- pygeai/tests/snippets/evaluation/plan/complete_workflow_example.py +5 -5
- pygeai/tests/snippets/evaluation/result/complete_workflow_example.py +3 -3
- pygeai/tests/snippets/lab/agentic_flow_example_1.py +1 -1
- pygeai/tests/snippets/lab/agentic_flow_example_2.py +3 -4
- pygeai/tests/snippets/lab/agents/create_agent_with_permissions.py +2 -2
- pygeai/tests/snippets/lab/agents/delete_agent.py +1 -2
- pygeai/tests/snippets/lab/agents/get_agent.py +1 -1
- pygeai/tests/snippets/lab/agents/get_agent_with_new_fields.py +10 -10
- pygeai/tests/snippets/lab/agents/get_sharing_link.py +0 -1
- pygeai/tests/snippets/lab/agents/list_agents.py +1 -1
- pygeai/tests/snippets/lab/agents/publish_agent_revision.py +0 -1
- pygeai/tests/snippets/lab/agents/update_agent_properties.py +1 -1
- pygeai/tests/snippets/lab/crud_ui.py +3 -5
- pygeai/tests/snippets/lab/processes/kbs/get_kb.py +0 -1
- pygeai/tests/snippets/lab/processes/kbs/list_kbs.py +0 -1
- pygeai/tests/snippets/lab/processes/list_processes.py +1 -1
- pygeai/tests/snippets/lab/samples/summarize_files.py +0 -3
- pygeai/tests/snippets/lab/strategies/get_reasoning_strategy.py +0 -1
- pygeai/tests/snippets/lab/strategies/list_reasoning_strategies.py +1 -1
- pygeai/tests/snippets/lab/tools/get_tool.py +1 -1
- pygeai/tests/snippets/lab/tools/publish_tool_revision.py +0 -1
- pygeai/tests/snippets/lab/tools/set_parameters.py +1 -2
- pygeai/tests/snippets/lab/use_cases/c_code_fixer_agent_flow.py +2 -3
- pygeai/tests/snippets/lab/use_cases/file_summarizer_example_2.py +1 -1
- pygeai/tests/snippets/lab/use_cases/update_cli_expert.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_lab_expert.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_web_designer.py +0 -1
- pygeai/tests/snippets/lab/use_cases/update_web_reader.py +0 -1
- pygeai/tests/snippets/migrate/orchestrator_examples.py +1 -1
- {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/METADATA +32 -7
- {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/RECORD +217 -206
- {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/WHEEL +0 -0
- {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/entry_points.txt +0 -0
- {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.6.0b13.dist-info → pygeai-0.6.1.dist-info}/top_level.txt +0 -0
pygeai/core/singleton.py
CHANGED
|
@@ -8,3 +8,27 @@ class Singleton(type):
|
|
|
8
8
|
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
|
9
9
|
|
|
10
10
|
return cls._instances[cls]
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def reset_instance(mcs, cls):
|
|
14
|
+
"""
|
|
15
|
+
Reset the singleton instance for a specific class.
|
|
16
|
+
|
|
17
|
+
This is intended for testing purposes to ensure proper isolation
|
|
18
|
+
between tests. In production code, singletons persist for the
|
|
19
|
+
application lifetime.
|
|
20
|
+
|
|
21
|
+
:param cls: The class whose singleton instance should be reset
|
|
22
|
+
"""
|
|
23
|
+
if cls in mcs._instances:
|
|
24
|
+
del mcs._instances[cls]
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def reset_all_instances(mcs):
|
|
28
|
+
"""
|
|
29
|
+
Reset all singleton instances.
|
|
30
|
+
|
|
31
|
+
This is intended for testing purposes to ensure proper isolation
|
|
32
|
+
between tests. Use with caution as it clears all singleton caches.
|
|
33
|
+
"""
|
|
34
|
+
mcs._instances.clear()
|
pygeai/dbg/__init__.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from pygeai.dbg.debugger import Debugger, Breakpoint
|
|
1
|
+
from pygeai.dbg.debugger import Debugger, Breakpoint, debug_file, debug_module
|
|
2
2
|
|
|
3
|
-
__all__ = ['Debugger', 'Breakpoint']
|
|
3
|
+
__all__ = ['Debugger', 'Breakpoint', 'debug_file', 'debug_module']
|
pygeai/dbg/debugger.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import sys
|
|
3
3
|
import inspect
|
|
4
|
-
import readline
|
|
5
4
|
import pprint
|
|
5
|
+
import argparse
|
|
6
6
|
from types import FrameType
|
|
7
|
-
from typing import Optional, Any, Callable,
|
|
8
|
-
from dataclasses import dataclass
|
|
7
|
+
from typing import Optional, Any, Callable, Dict, List, Tuple
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from importlib import util
|
|
9
10
|
|
|
10
11
|
from pygeai.cli.geai import main as geai
|
|
11
12
|
from pygeai.core.utils.console import Console
|
|
@@ -62,16 +63,19 @@ class Debugger:
|
|
|
62
63
|
- Readline support for command history
|
|
63
64
|
"""
|
|
64
65
|
|
|
65
|
-
def __init__(self, target: Optional[Callable] = None, module_filter: str = "pygeai"):
|
|
66
|
+
def __init__(self, target: Optional[Callable] = None, module_filter: str = "pygeai", verbose: bool = False, log_level: str = 'DEBUG'):
|
|
66
67
|
"""
|
|
67
68
|
Initialize the debugger.
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
:param target: Optional[Callable] - The callable to debug. If None, defaults to pygeai.cli.geai.main (optional).
|
|
71
|
+
:param module_filter: str - Only trace modules starting with this prefix (for performance). Empty string traces all modules. Use '__main__' to trace only the main script (default is 'pygeai').
|
|
72
|
+
:param verbose: bool - If True, enable logging for pygeai modules (default is False).
|
|
73
|
+
:param log_level: str - Log level for verbose mode: 'DEBUG', 'INFO', 'WARNING', 'ERROR' (default is 'DEBUG').
|
|
72
74
|
"""
|
|
73
75
|
self.target = target or geai
|
|
74
76
|
self.module_filter = module_filter
|
|
77
|
+
self.verbose = verbose
|
|
78
|
+
self.log_level = getattr(logging, log_level.upper(), logging.DEBUG)
|
|
75
79
|
self._setup_logging()
|
|
76
80
|
self.logger = logging.getLogger('geai.dbg')
|
|
77
81
|
|
|
@@ -106,9 +110,31 @@ class Debugger:
|
|
|
106
110
|
console_handler.setFormatter(formatter)
|
|
107
111
|
logger.addHandler(console_handler)
|
|
108
112
|
logger.propagate = False
|
|
113
|
+
|
|
114
|
+
# If verbose mode, enable logging for pygeai modules at specified level
|
|
115
|
+
if self.verbose:
|
|
116
|
+
# Configure root logger to show at specified log level
|
|
117
|
+
root_logger = logging.getLogger()
|
|
118
|
+
if not root_logger.handlers:
|
|
119
|
+
root_logger.setLevel(self.log_level)
|
|
120
|
+
console_handler = logging.StreamHandler()
|
|
121
|
+
console_handler.setLevel(self.log_level)
|
|
122
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
123
|
+
console_handler.setFormatter(formatter)
|
|
124
|
+
root_logger.addHandler(console_handler)
|
|
125
|
+
|
|
126
|
+
# Ensure pygeai logger propagates to root
|
|
127
|
+
pygeai_logger = logging.getLogger('pygeai')
|
|
128
|
+
pygeai_logger.setLevel(self.log_level)
|
|
129
|
+
pygeai_logger.propagate = True
|
|
109
130
|
|
|
110
131
|
def _setup_readline(self):
|
|
111
132
|
"""Setup readline for command history and tab completion."""
|
|
133
|
+
if not util.find_spec("readline"):
|
|
134
|
+
self.logger.debug("Readline not available (not supported on this platform)")
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
import readline
|
|
112
138
|
try:
|
|
113
139
|
import os
|
|
114
140
|
histfile = os.path.expanduser("~/.geai_dbg_history")
|
|
@@ -145,13 +171,10 @@ class Debugger:
|
|
|
145
171
|
"""
|
|
146
172
|
Add a breakpoint by module and/or function name.
|
|
147
173
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
Returns:
|
|
154
|
-
The created Breakpoint object
|
|
174
|
+
:param module: Optional[str] - Module name to break on. None for any module (optional).
|
|
175
|
+
:param function_name: Optional[str] - Function name to break on. None for any function (optional).
|
|
176
|
+
:param condition: Optional[str] - Optional condition expression in Python code. Breakpoint only triggers if condition evaluates to True (optional).
|
|
177
|
+
:return: Breakpoint - The created Breakpoint object.
|
|
155
178
|
"""
|
|
156
179
|
key = (module, function_name)
|
|
157
180
|
if key in self.breakpoints:
|
|
@@ -206,6 +229,8 @@ class Debugger:
|
|
|
206
229
|
"""Check if we should trace this module based on filter."""
|
|
207
230
|
if not module:
|
|
208
231
|
return False
|
|
232
|
+
if not self.module_filter:
|
|
233
|
+
return True
|
|
209
234
|
return module.startswith(self.module_filter)
|
|
210
235
|
|
|
211
236
|
def _check_condition(self, bp: Breakpoint, frame: FrameType) -> bool:
|
|
@@ -214,7 +239,6 @@ class Debugger:
|
|
|
214
239
|
return True
|
|
215
240
|
|
|
216
241
|
try:
|
|
217
|
-
# Evaluate condition in frame's context
|
|
218
242
|
result = eval(bp.condition, frame.f_globals, frame.f_locals)
|
|
219
243
|
return bool(result)
|
|
220
244
|
except Exception as e:
|
|
@@ -234,17 +258,14 @@ class Debugger:
|
|
|
234
258
|
"""Trace function calls to intercept execution."""
|
|
235
259
|
module = frame.f_globals.get('__name__')
|
|
236
260
|
|
|
237
|
-
# Performance optimization: only trace filtered modules
|
|
238
261
|
if not self._should_trace_module(module):
|
|
239
262
|
return None
|
|
240
263
|
|
|
241
264
|
function_name = frame.f_code.co_name
|
|
242
265
|
|
|
243
|
-
# Handle different event types
|
|
244
266
|
if event == 'call':
|
|
245
267
|
self.current_depth += 1
|
|
246
268
|
|
|
247
|
-
# Check breakpoints
|
|
248
269
|
should_break = False
|
|
249
270
|
for bp in self.breakpoints.values():
|
|
250
271
|
if bp.matches(module, function_name):
|
|
@@ -265,7 +286,6 @@ class Debugger:
|
|
|
265
286
|
elif event == 'return':
|
|
266
287
|
self.current_depth -= 1
|
|
267
288
|
|
|
268
|
-
# Handle step-out (return from function)
|
|
269
289
|
if self.step_mode == 'return' and frame == self.step_frame:
|
|
270
290
|
self.step_mode = None
|
|
271
291
|
self.paused = True
|
|
@@ -276,7 +296,6 @@ class Debugger:
|
|
|
276
296
|
self.paused = False
|
|
277
297
|
|
|
278
298
|
elif event == 'line':
|
|
279
|
-
# Handle step and next
|
|
280
299
|
if self.step_mode == 'step':
|
|
281
300
|
self.step_mode = None
|
|
282
301
|
self.paused = True
|
|
@@ -372,7 +391,6 @@ class Debugger:
|
|
|
372
391
|
cmd = parts[0]
|
|
373
392
|
args = parts[1] if len(parts) > 1 else ""
|
|
374
393
|
|
|
375
|
-
# Control flow commands
|
|
376
394
|
if cmd in ('continue', 'c'):
|
|
377
395
|
break
|
|
378
396
|
elif cmd in ('quit', 'q'):
|
|
@@ -383,7 +401,6 @@ class Debugger:
|
|
|
383
401
|
sys.settrace(None)
|
|
384
402
|
break
|
|
385
403
|
|
|
386
|
-
# Stepping commands
|
|
387
404
|
elif cmd in ('step', 's'):
|
|
388
405
|
self.step_mode = 'step'
|
|
389
406
|
self.step_depth = self.current_depth
|
|
@@ -397,7 +414,6 @@ class Debugger:
|
|
|
397
414
|
self.step_frame = frame
|
|
398
415
|
break
|
|
399
416
|
|
|
400
|
-
# Stack navigation
|
|
401
417
|
elif cmd in ('up', 'u'):
|
|
402
418
|
self._move_frame(1)
|
|
403
419
|
elif cmd in ('down', 'd'):
|
|
@@ -405,12 +421,10 @@ class Debugger:
|
|
|
405
421
|
elif cmd in ('where', 'w', 'bt', 'backtrace'):
|
|
406
422
|
self._print_stack_trace()
|
|
407
423
|
|
|
408
|
-
# Source display
|
|
409
424
|
elif cmd in ('list', 'l'):
|
|
410
425
|
context = int(args) if args.isdigit() else 10
|
|
411
426
|
self._print_source(self.current_frame, context)
|
|
412
427
|
|
|
413
|
-
# Variable inspection
|
|
414
428
|
elif cmd in ('print', 'p'):
|
|
415
429
|
if not args:
|
|
416
430
|
Console.write_stdout("Usage: p <expression>")
|
|
@@ -437,7 +451,6 @@ class Debugger:
|
|
|
437
451
|
|
|
438
452
|
elif cmd in ('globals', 'glob'):
|
|
439
453
|
Console.write_stdout("\nGlobal variables:")
|
|
440
|
-
# Filter out builtins
|
|
441
454
|
filtered = {k: v for k, v in self.current_frame.f_globals.items()
|
|
442
455
|
if not k.startswith('__')}
|
|
443
456
|
pprint.pprint(filtered)
|
|
@@ -448,10 +461,8 @@ class Debugger:
|
|
|
448
461
|
for arg in arginfo.args:
|
|
449
462
|
Console.write_stdout(f" {arg} = {repr(self.current_frame.f_locals.get(arg))}")
|
|
450
463
|
|
|
451
|
-
# Breakpoint management
|
|
452
464
|
elif cmd in ('break', 'b'):
|
|
453
465
|
if not args:
|
|
454
|
-
# List breakpoints
|
|
455
466
|
bps = self.list_breakpoints()
|
|
456
467
|
if bps:
|
|
457
468
|
Console.write_stdout("\nBreakpoints:")
|
|
@@ -460,7 +471,6 @@ class Debugger:
|
|
|
460
471
|
else:
|
|
461
472
|
Console.write_stdout("No breakpoints set.")
|
|
462
473
|
else:
|
|
463
|
-
# Parse breakpoint specification: module:function or just function
|
|
464
474
|
if ':' in args:
|
|
465
475
|
mod, func = args.split(':', 1)
|
|
466
476
|
mod = mod.strip() or None
|
|
@@ -509,7 +519,6 @@ class Debugger:
|
|
|
509
519
|
func = args.strip()
|
|
510
520
|
self.disable_breakpoint(module=mod, function_name=func)
|
|
511
521
|
|
|
512
|
-
# Legacy commands
|
|
513
522
|
elif cmd in ('breakpoint-module', 'bm'):
|
|
514
523
|
self.logger.info("Adding breakpoint on module")
|
|
515
524
|
module_name = input("(geai-dbg) Enter module name (or press Enter for any module): ").strip()
|
|
@@ -528,20 +537,17 @@ class Debugger:
|
|
|
528
537
|
self.logger.info("Listing available modules")
|
|
529
538
|
modules = [m for m in sys.modules if m.startswith(self.module_filter)]
|
|
530
539
|
Console.write_stdout(f"\nAvailable modules ({len(modules)}):")
|
|
531
|
-
for mod in sorted(modules)[:50]:
|
|
540
|
+
for mod in sorted(modules)[:50]:
|
|
532
541
|
Console.write_stdout(f" {mod}")
|
|
533
542
|
if len(modules) > 50:
|
|
534
543
|
Console.write_stdout(f" ... and {len(modules) - 50} more")
|
|
535
544
|
|
|
536
|
-
# Help
|
|
537
545
|
elif cmd in ('help', 'h', '?'):
|
|
538
546
|
self._print_help()
|
|
539
547
|
|
|
540
|
-
# Execute arbitrary Python code
|
|
541
548
|
else:
|
|
542
549
|
self.logger.info(f"Executing interactive command: {command}")
|
|
543
550
|
try:
|
|
544
|
-
# Try exec first, if it fails try eval and print result
|
|
545
551
|
try:
|
|
546
552
|
exec(command, self.current_frame.f_globals, self.current_frame.f_locals)
|
|
547
553
|
except SyntaxError:
|
|
@@ -626,11 +632,243 @@ Examples:
|
|
|
626
632
|
sys.settrace(None)
|
|
627
633
|
|
|
628
634
|
|
|
635
|
+
def debug_file(
|
|
636
|
+
filepath: str,
|
|
637
|
+
args: Optional[List[str]] = None,
|
|
638
|
+
module_filter: Optional[str] = None,
|
|
639
|
+
breakpoint_specs: Optional[List[Tuple[Optional[str], Optional[str]]]] = None,
|
|
640
|
+
verbose: bool = False,
|
|
641
|
+
log_level: str = 'DEBUG'
|
|
642
|
+
) -> Debugger:
|
|
643
|
+
"""
|
|
644
|
+
Debug a Python file by executing it under the debugger.
|
|
645
|
+
|
|
646
|
+
:param filepath: str - Path to the Python file to debug (required).
|
|
647
|
+
:param args: Optional[List[str]] - Command-line arguments to pass to the script (optional).
|
|
648
|
+
:param module_filter: Optional[str] - Module prefix to trace. None auto-detects based on file content (optional).
|
|
649
|
+
:param breakpoint_specs: Optional[List[Tuple[Optional[str], Optional[str]]]] - List of (module, function) tuples for initial breakpoints (optional).
|
|
650
|
+
:param verbose: bool - Enable verbose logging (default False).
|
|
651
|
+
:param log_level: str - Log level for verbose mode: 'DEBUG', 'INFO', 'WARNING', 'ERROR' (default 'DEBUG').
|
|
652
|
+
:return: Debugger - Configured Debugger instance ready to run.
|
|
653
|
+
:raises FileNotFoundError: If the specified file doesn't exist.
|
|
654
|
+
"""
|
|
655
|
+
import os
|
|
656
|
+
|
|
657
|
+
if not os.path.isfile(filepath):
|
|
658
|
+
raise FileNotFoundError(f"File not found: {filepath}")
|
|
659
|
+
|
|
660
|
+
import runpy
|
|
661
|
+
|
|
662
|
+
old_argv = sys.argv.copy()
|
|
663
|
+
sys.argv = [filepath] + (args or [])
|
|
664
|
+
|
|
665
|
+
def target():
|
|
666
|
+
try:
|
|
667
|
+
# Use runpy to properly execute as __main__ module
|
|
668
|
+
# This ensures unittest.main() and similar tools work correctly
|
|
669
|
+
runpy.run_path(filepath, run_name='__main__')
|
|
670
|
+
finally:
|
|
671
|
+
sys.argv = old_argv
|
|
672
|
+
|
|
673
|
+
# Auto-detect module filter based on file content
|
|
674
|
+
if module_filter is None:
|
|
675
|
+
with open(filepath, 'r') as f:
|
|
676
|
+
content = f.read()
|
|
677
|
+
if 'pygeai' in content or 'from pygeai' in content or 'import pygeai' in content:
|
|
678
|
+
module_filter = ''
|
|
679
|
+
else:
|
|
680
|
+
module_filter = '__main__'
|
|
681
|
+
|
|
682
|
+
dbg = Debugger(target=target, module_filter=module_filter, verbose=verbose, log_level=log_level)
|
|
683
|
+
|
|
684
|
+
if breakpoint_specs:
|
|
685
|
+
for module, function in breakpoint_specs:
|
|
686
|
+
dbg.add_breakpoint(module=module, function_name=function)
|
|
687
|
+
|
|
688
|
+
return dbg
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
def debug_module(
|
|
692
|
+
module_name: str,
|
|
693
|
+
function_name: str = 'main',
|
|
694
|
+
args: Optional[List[str]] = None,
|
|
695
|
+
module_filter: Optional[str] = None
|
|
696
|
+
) -> Debugger:
|
|
697
|
+
"""
|
|
698
|
+
Debug a specific module and function by importing and executing it under the debugger.
|
|
699
|
+
|
|
700
|
+
:param module_name: str - Fully qualified module name, e.g., 'pygeai.cli.geai' (required).
|
|
701
|
+
:param function_name: str - Function to call within the module (default is 'main').
|
|
702
|
+
:param args: Optional[List[str]] - Command-line arguments to pass (optional).
|
|
703
|
+
:param module_filter: Optional[str] - Module prefix to trace. None defaults to first part of module_name (optional).
|
|
704
|
+
:return: Debugger - Configured Debugger instance with an automatic breakpoint on the target function.
|
|
705
|
+
:raises ImportError: If the module or function cannot be imported.
|
|
706
|
+
"""
|
|
707
|
+
import importlib
|
|
708
|
+
|
|
709
|
+
old_argv = sys.argv.copy()
|
|
710
|
+
sys.argv = [module_name] + (args or [])
|
|
711
|
+
|
|
712
|
+
try:
|
|
713
|
+
module = importlib.import_module(module_name)
|
|
714
|
+
func = getattr(module, function_name)
|
|
715
|
+
except (ImportError, AttributeError) as e:
|
|
716
|
+
raise ImportError(f"Cannot import {module_name}.{function_name}: {e}")
|
|
717
|
+
|
|
718
|
+
def target():
|
|
719
|
+
try:
|
|
720
|
+
func()
|
|
721
|
+
finally:
|
|
722
|
+
sys.argv = old_argv
|
|
723
|
+
|
|
724
|
+
if module_filter is None:
|
|
725
|
+
module_filter = module_name.split('.')[0]
|
|
726
|
+
|
|
727
|
+
dbg = Debugger(target=target, module_filter=module_filter)
|
|
728
|
+
dbg.add_breakpoint(module=module_name, function_name=function_name)
|
|
729
|
+
|
|
730
|
+
return dbg
|
|
731
|
+
|
|
732
|
+
|
|
629
733
|
def main():
|
|
630
|
-
"""
|
|
631
|
-
dbg
|
|
632
|
-
|
|
633
|
-
|
|
734
|
+
"""
|
|
735
|
+
Entry point for geai-dbg command.
|
|
736
|
+
|
|
737
|
+
Usage:
|
|
738
|
+
geai-dbg Debug geai CLI (default)
|
|
739
|
+
geai-dbg script.py [args...] Debug a Python file
|
|
740
|
+
geai-dbg -m module:func [args...] Debug a module function
|
|
741
|
+
geai-dbg -h Show help
|
|
742
|
+
"""
|
|
743
|
+
parser = argparse.ArgumentParser(
|
|
744
|
+
prog='geai-dbg',
|
|
745
|
+
description='Interactive debugger for PyGEAI applications',
|
|
746
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
747
|
+
epilog="""
|
|
748
|
+
Examples:
|
|
749
|
+
geai-dbg Debug the geai CLI
|
|
750
|
+
geai-dbg script.py arg1 arg2 Debug a Python file with arguments
|
|
751
|
+
geai-dbg -v script.py Debug with verbose logging (DEBUG level)
|
|
752
|
+
geai-dbg -v --log-level INFO script.py Debug with INFO level logging
|
|
753
|
+
geai-dbg -m pygeai.cli.geai:main Debug a specific module function
|
|
754
|
+
geai-dbg -b main script.py Break on 'main' function
|
|
755
|
+
geai-dbg --filter pygeai script.py Only trace pygeai modules
|
|
756
|
+
"""
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
parser.add_argument(
|
|
760
|
+
'target',
|
|
761
|
+
nargs='?',
|
|
762
|
+
default=None,
|
|
763
|
+
help='Python file to debug (omit to debug geai CLI)'
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
parser.add_argument(
|
|
767
|
+
'args',
|
|
768
|
+
nargs='*',
|
|
769
|
+
help='Arguments to pass to the target'
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
parser.add_argument(
|
|
773
|
+
'-m', '--module',
|
|
774
|
+
metavar='MODULE:FUNC',
|
|
775
|
+
help='Debug a module function (format: module.path:function_name)'
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
parser.add_argument(
|
|
779
|
+
'-b', '--break',
|
|
780
|
+
dest='breakpoints',
|
|
781
|
+
action='append',
|
|
782
|
+
metavar='BREAKPOINT',
|
|
783
|
+
help='Set initial breakpoint (format: [module:]function, can be repeated)'
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
parser.add_argument(
|
|
787
|
+
'--filter',
|
|
788
|
+
metavar='PREFIX',
|
|
789
|
+
help='Module prefix to trace (default: auto-detect)'
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
parser.add_argument(
|
|
793
|
+
'--trace-all',
|
|
794
|
+
action='store_true',
|
|
795
|
+
help='Trace all modules (warning: may be slow)'
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
parser.add_argument(
|
|
799
|
+
'-v', '--verbose',
|
|
800
|
+
action='store_true',
|
|
801
|
+
help='Enable verbose logging for pygeai modules'
|
|
802
|
+
)
|
|
803
|
+
|
|
804
|
+
parser.add_argument(
|
|
805
|
+
'--log-level',
|
|
806
|
+
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
|
|
807
|
+
default='DEBUG',
|
|
808
|
+
help='Log level for verbose mode (default: DEBUG)'
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
parsed_args = parser.parse_args()
|
|
812
|
+
|
|
813
|
+
try:
|
|
814
|
+
if parsed_args.module:
|
|
815
|
+
if ':' in parsed_args.module:
|
|
816
|
+
module_name, func_name = parsed_args.module.split(':', 1)
|
|
817
|
+
else:
|
|
818
|
+
module_name = parsed_args.module
|
|
819
|
+
func_name = 'main'
|
|
820
|
+
|
|
821
|
+
dbg = debug_module(
|
|
822
|
+
module_name=module_name,
|
|
823
|
+
function_name=func_name,
|
|
824
|
+
args=parsed_args.args,
|
|
825
|
+
module_filter='' if parsed_args.trace_all else parsed_args.filter
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
elif parsed_args.target:
|
|
829
|
+
breakpoint_specs = []
|
|
830
|
+
if parsed_args.breakpoints:
|
|
831
|
+
for bp in parsed_args.breakpoints:
|
|
832
|
+
if ':' in bp:
|
|
833
|
+
mod, func = bp.split(':', 1)
|
|
834
|
+
breakpoint_specs.append((mod or None, func or None))
|
|
835
|
+
else:
|
|
836
|
+
breakpoint_specs.append((None, bp))
|
|
837
|
+
|
|
838
|
+
dbg = debug_file(
|
|
839
|
+
filepath=parsed_args.target,
|
|
840
|
+
args=parsed_args.args,
|
|
841
|
+
module_filter='' if parsed_args.trace_all else parsed_args.filter,
|
|
842
|
+
breakpoint_specs=breakpoint_specs if breakpoint_specs else None,
|
|
843
|
+
verbose=parsed_args.verbose,
|
|
844
|
+
log_level=parsed_args.log_level
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
else:
|
|
848
|
+
dbg = Debugger(module_filter='pygeai')
|
|
849
|
+
dbg.add_breakpoint(module='pygeai.cli.geai', function_name='main')
|
|
850
|
+
|
|
851
|
+
if parsed_args.breakpoints and not parsed_args.target:
|
|
852
|
+
for bp in parsed_args.breakpoints:
|
|
853
|
+
if ':' in bp:
|
|
854
|
+
mod, func = bp.split(':', 1)
|
|
855
|
+
dbg.add_breakpoint(module=mod or None, function_name=func or None)
|
|
856
|
+
else:
|
|
857
|
+
dbg.add_breakpoint(function_name=bp)
|
|
858
|
+
|
|
859
|
+
Console.write_stdout("GEAI Debugger started. Type 'h' for help, 'c' to continue, 'q' to quit.")
|
|
860
|
+
|
|
861
|
+
dbg.run()
|
|
862
|
+
|
|
863
|
+
except FileNotFoundError as e:
|
|
864
|
+
Console.write_stdout(f"Error: {e}")
|
|
865
|
+
sys.exit(1)
|
|
866
|
+
except ImportError as e:
|
|
867
|
+
Console.write_stdout(f"Error: {e}")
|
|
868
|
+
sys.exit(1)
|
|
869
|
+
except Exception as e:
|
|
870
|
+
logging.getLogger('geai.dbg').error(f"Debugger failed: {e}", exc_info=True)
|
|
871
|
+
sys.exit(1)
|
|
634
872
|
|
|
635
873
|
|
|
636
874
|
if __name__ == "__main__":
|
pygeai/evaluation/clients.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from pygeai.core.base.clients import BaseClient
|
|
2
|
-
from pygeai.core.base.session import Session
|
|
3
2
|
from pygeai.core.common.exceptions import MissingRequirementException
|
|
4
|
-
from pygeai.core.services.rest import
|
|
5
|
-
from pygeai.core.utils.validators import validate_status_code
|
|
3
|
+
from pygeai.core.services.rest import GEAIApiService
|
|
6
4
|
|
|
7
5
|
|
|
8
6
|
class EvaluationClient(BaseClient):
|
|
@@ -16,4 +14,4 @@ class EvaluationClient(BaseClient):
|
|
|
16
14
|
|
|
17
15
|
self.session.eval_url = eval_url
|
|
18
16
|
token = self.session.access_token if self.session.access_token else self.session.api_key
|
|
19
|
-
self.api_service =
|
|
17
|
+
self.api_service = GEAIApiService(base_url=self.session.eval_url, token=token, project_id=self.session.project_id)
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
1
|
from pygeai.evaluation.clients import EvaluationClient
|
|
4
2
|
from pygeai.evaluation.plan.endpoints import LIST_EVALUATION_PLANS, CREATE_EVALUATION_PLAN, GET_EVALUATION_PLAN, \
|
|
5
3
|
UPDATE_EVALUATION_PLAN, DELETE_EVALUATION_PLAN, LIST_EVALUATION_PLAN_SYSTEM_METRICS, \
|
pygeai/gam/clients.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
from pygeai import logger
|
|
3
1
|
from pygeai.core.base.clients import BaseClient
|
|
4
|
-
from pygeai.core.common.exceptions import MissingRequirementException
|
|
2
|
+
from pygeai.core.common.exceptions import MissingRequirementException
|
|
5
3
|
from pygeai.core.utils.validators import validate_status_code
|
|
6
4
|
from pygeai.core.utils.parsers import parse_json_response
|
|
7
5
|
from pygeai.gam.endpoints import GET_ACCESS_TOKEN_V2, GET_USER_INFO_V2, IDP_SIGNIN_V1
|
pygeai/health/clients.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
from pygeai import logger
|
|
3
1
|
from pygeai.core.base.clients import BaseClient
|
|
4
|
-
|
|
2
|
+
|
|
5
3
|
from pygeai.core.utils.validators import validate_status_code
|
|
6
4
|
from pygeai.core.utils.parsers import parse_json_response
|
|
7
5
|
from pygeai.health.endpoints import STATUS_CHECK_V1
|
pygeai/lab/clients.py
CHANGED
|
@@ -2,7 +2,6 @@ from pygeai import logger
|
|
|
2
2
|
from pygeai.admin.clients import AdminClient
|
|
3
3
|
from pygeai.core.base.clients import BaseClient
|
|
4
4
|
from pygeai.core.common.exceptions import APIError
|
|
5
|
-
from pygeai.core.utils.validators import validate_status_code
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
class AILabClient(BaseClient):
|
pygeai/lab/managers.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Union, Optional, List
|
|
2
2
|
|
|
3
3
|
from pygeai import logger
|
|
4
|
-
from pygeai.admin.clients import AdminClient
|
|
5
4
|
from pygeai.core.base.mappers import ResponseMapper
|
|
6
5
|
from pygeai.core.base.responses import EmptyResponse
|
|
7
6
|
from pygeai.core.common.exceptions import APIError, MissingRequirementException
|
pygeai/lab/models.py
CHANGED
pygeai/lab/strategies/clients.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
1
|
from pygeai import logger
|
|
3
|
-
|
|
2
|
+
|
|
4
3
|
from pygeai.core.utils.validators import validate_status_code
|
|
5
4
|
from pygeai.core.utils.parsers import parse_json_response
|
|
6
5
|
from pygeai.lab.clients import AILabClient
|
pygeai/lab/tools/clients.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
3
|
from pygeai import logger
|
|
4
|
-
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
4
|
+
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
5
5
|
from pygeai.core.utils.validators import validate_status_code
|
|
6
6
|
from pygeai.core.utils.parsers import parse_json_response
|
|
7
7
|
from pygeai.lab.constants import VALID_SCOPES, VALID_ACCESS_SCOPES, VALID_REPORT_EVENTS
|
|
@@ -278,7 +278,7 @@ class ToolClient(AILabClient):
|
|
|
278
278
|
:raises Exception: May be raised by `api_service.put` for network issues, authentication errors, or server-side problems (not caught here).
|
|
279
279
|
"""
|
|
280
280
|
if not (tool_id or name):
|
|
281
|
-
raise ValueError(
|
|
281
|
+
raise ValueError("Either tool ID or tool Name must be defined in order to update tool.")
|
|
282
282
|
if scope and scope not in VALID_SCOPES:
|
|
283
283
|
raise ValueError(f"Scope must be one of {', '.join(VALID_SCOPES)}.")
|
|
284
284
|
if access_scope and access_scope not in VALID_ACCESS_SCOPES:
|
pygeai/lab/tools/mappers.py
CHANGED
|
@@ -69,7 +69,7 @@ class ToolMapper:
|
|
|
69
69
|
if isinstance(open_api_json, str):
|
|
70
70
|
try:
|
|
71
71
|
open_api_json = json.loads(open_api_json)
|
|
72
|
-
except JSONDecodeError
|
|
72
|
+
except JSONDecodeError:
|
|
73
73
|
raise ValueError("open_api_json must be a valid JSON string or a dict")
|
|
74
74
|
|
|
75
75
|
report_events = tool_data.get("reportEvents", "None")
|
pygeai/migration/strategies.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
from abc import ABC, abstractmethod
|
|
3
2
|
from typing import Optional
|
|
4
3
|
|
|
@@ -111,7 +110,7 @@ class ProjectMigrationStrategy(MigrationStrategy):
|
|
|
111
110
|
new_project.name = self.to_project_name
|
|
112
111
|
new_project.email = self.admin_email
|
|
113
112
|
|
|
114
|
-
logger.debug(
|
|
113
|
+
logger.debug("Creating project with destination manager:")
|
|
115
114
|
logger.debug(f" - API Key (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
116
115
|
logger.debug(f" - Base URL: {self.to_instance}")
|
|
117
116
|
logger.debug(f" - Project Name: {self.to_project_name}")
|
|
@@ -122,10 +121,10 @@ class ProjectMigrationStrategy(MigrationStrategy):
|
|
|
122
121
|
except Exception as e:
|
|
123
122
|
error_msg = f"Create project failed: {e}"
|
|
124
123
|
logger.error(error_msg)
|
|
125
|
-
logger.error(
|
|
124
|
+
logger.error(" - Operation: Create project")
|
|
126
125
|
logger.error(f" - Base URL: {self.to_instance}")
|
|
127
126
|
logger.error(f" - API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
128
|
-
Console.write_stderr(
|
|
127
|
+
Console.write_stderr("\nDEBUG: Operation failed: Create project")
|
|
129
128
|
Console.write_stderr(f"DEBUG: Base URL: {self.to_instance}")
|
|
130
129
|
Console.write_stderr(f"DEBUG: API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
131
130
|
raise ValueError(error_msg) from e
|
|
@@ -133,10 +132,10 @@ class ProjectMigrationStrategy(MigrationStrategy):
|
|
|
133
132
|
if isinstance(response, ErrorListResponse):
|
|
134
133
|
error_detail = response.to_dict()
|
|
135
134
|
logger.error(f"Create project returned error response: {error_detail}")
|
|
136
|
-
logger.error(
|
|
135
|
+
logger.error(" - Operation: Create project")
|
|
137
136
|
logger.error(f" - Base URL: {self.to_instance}")
|
|
138
137
|
logger.error(f" - API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
139
|
-
Console.write_stderr(
|
|
138
|
+
Console.write_stderr("\nDEBUG: Operation failed: Create project")
|
|
140
139
|
Console.write_stderr(f"DEBUG: Base URL: {self.to_instance}")
|
|
141
140
|
Console.write_stderr(f"DEBUG: API Key used (first 20 chars): {self.to_api_key[:20] if self.to_api_key else 'None'}...")
|
|
142
141
|
raise ValueError(f"Failed to create project: {error_detail}")
|