claude-mpm 4.5.11__py3-none-any.whl → 4.5.13__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_ENGINEER.md +47 -0
- claude_mpm/agents/BASE_QA.md +60 -0
- claude_mpm/agents/frontmatter_validator.py +4 -4
- claude_mpm/agents/templates/nextjs_engineer.json +2 -2
- claude_mpm/agents/templates/qa.json +13 -3
- claude_mpm/agents/templates/react_engineer.json +2 -2
- claude_mpm/agents/templates/typescript_engineer.json +2 -2
- claude_mpm/agents/templates/web_qa.json +14 -3
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +6 -6
- claude_mpm/cli/commands/aggregate.py +4 -4
- claude_mpm/cli/commands/analyze.py +2 -2
- claude_mpm/cli/commands/analyze_code.py +1 -1
- claude_mpm/cli/commands/cleanup.py +3 -3
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +14 -14
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +3 -3
- claude_mpm/cli/commands/doctor.py +1 -1
- claude_mpm/cli/commands/mcp.py +7 -7
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +2 -2
- claude_mpm/cli/commands/mcp_external_commands.py +2 -2
- claude_mpm/cli/commands/mcp_install_commands.py +3 -3
- claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +3 -3
- claude_mpm/cli/commands/monitor.py +1 -1
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/interactive/agent_wizard.py +1 -1
- claude_mpm/cli/parsers/search_parser.py +1 -1
- claude_mpm/cli/shared/argument_patterns.py +2 -2
- claude_mpm/cli/shared/base_command.py +1 -1
- claude_mpm/cli/startup_logging.py +6 -4
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/socketio_config.py +2 -2
- claude_mpm/core/agent_session_manager.py +2 -2
- claude_mpm/core/api_validator.py +3 -3
- claude_mpm/core/base_service.py +10 -1
- claude_mpm/core/cache.py +2 -2
- claude_mpm/core/config.py +4 -4
- claude_mpm/core/config_aliases.py +4 -4
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/error_handler.py +1 -1
- claude_mpm/core/file_utils.py +5 -5
- claude_mpm/core/framework/formatters/capability_generator.py +5 -5
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/framework/processors/template_processor.py +3 -3
- claude_mpm/core/framework_loader.py +2 -2
- claude_mpm/core/log_manager.py +4 -4
- claude_mpm/core/logger.py +2 -2
- claude_mpm/core/optimized_startup.py +1 -1
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/service_registry.py +2 -2
- claude_mpm/core/session_manager.py +3 -3
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/socketio_pool.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +2 -2
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +1 -1
- claude_mpm/hooks/claude_hooks/event_handlers.py +2 -2
- claude_mpm/hooks/claude_hooks/installer.py +9 -9
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +7 -2
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/init.py +4 -4
- claude_mpm/models/agent_session.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +5 -5
- claude_mpm/services/__init__.py +2 -2
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +6 -4
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +3 -3
- claude_mpm/services/agents/deployment/deployment_wrapper.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +5 -5
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/agents/registry/modification_tracker.py +19 -11
- claude_mpm/services/async_session_logger.py +1 -1
- claude_mpm/services/claude_session_logger.py +1 -1
- claude_mpm/services/cli/agent_listing_service.py +3 -3
- claude_mpm/services/cli/agent_validation_service.py +1 -1
- claude_mpm/services/cli/session_manager.py +2 -2
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/checks/agent_check.py +1 -1
- claude_mpm/services/diagnostics/checks/claude_code_check.py +2 -2
- claude_mpm/services/diagnostics/checks/common_issues_check.py +3 -3
- claude_mpm/services/diagnostics/checks/configuration_check.py +2 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +9 -9
- claude_mpm/services/diagnostics/checks/monitor_check.py +1 -1
- claude_mpm/services/diagnostics/doctor_reporter.py +1 -1
- claude_mpm/services/event_aggregator.py +1 -1
- claude_mpm/services/event_bus/event_bus.py +9 -2
- claude_mpm/services/events/consumers/dead_letter.py +2 -2
- claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
- claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
- claude_mpm/services/hook_installer_service.py +7 -7
- claude_mpm/services/infrastructure/context_preservation.py +7 -7
- claude_mpm/services/infrastructure/daemon_manager.py +5 -5
- claude_mpm/services/mcp_config_manager.py +10 -10
- claude_mpm/services/mcp_gateway/auto_configure.py +5 -5
- claude_mpm/services/mcp_gateway/config/config_loader.py +2 -2
- claude_mpm/services/mcp_gateway/config/configuration.py +5 -3
- claude_mpm/services/mcp_gateway/core/process_pool.py +3 -3
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
- claude_mpm/services/mcp_gateway/core/startup_verification.py +1 -1
- claude_mpm/services/mcp_gateway/main.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +2 -1
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +1 -1
- claude_mpm/services/mcp_gateway/tools/hello_world.py +1 -1
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +5 -5
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +2 -2
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/builder.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
- claude_mpm/services/memory/indexed_memory.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +9 -9
- claude_mpm/services/monitor/handlers/file.py +1 -1
- claude_mpm/services/monitor/handlers/hooks.py +3 -3
- claude_mpm/services/monitor/management/lifecycle.py +7 -7
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/orphan_detection.py +11 -16
- claude_mpm/services/port_manager.py +2 -2
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/archive_manager.py +17 -13
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/documentation_manager.py +4 -4
- claude_mpm/services/project/enhanced_analyzer.py +19 -8
- claude_mpm/services/project/registry.py +4 -4
- claude_mpm/services/project_port_allocator.py +7 -12
- claude_mpm/services/session_management_service.py +1 -1
- claude_mpm/services/socketio/event_normalizer.py +1 -1
- claude_mpm/services/socketio/handlers/code_analysis.py +14 -12
- claude_mpm/services/socketio/handlers/file.py +1 -1
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/server/core.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +4 -4
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
- claude_mpm/services/unified/config_strategies/config_schema.py +4 -4
- claude_mpm/services/unified/config_strategies/context_strategy.py +8 -6
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +10 -10
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +5 -5
- claude_mpm/services/unified/config_strategies/unified_config_service.py +8 -8
- claude_mpm/services/unified/config_strategies/validation_strategy.py +15 -15
- claude_mpm/services/unified/deployment_strategies/base.py +4 -4
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +15 -15
- claude_mpm/services/unified/deployment_strategies/local.py +11 -11
- claude_mpm/services/unified/deployment_strategies/utils.py +11 -9
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -9
- claude_mpm/services/unified/unified_config.py +5 -5
- claude_mpm/services/unified/unified_deployment.py +2 -2
- claude_mpm/services/utility_service.py +1 -1
- claude_mpm/services/version_control/conflict_resolution.py +2 -2
- claude_mpm/services/version_control/git_operations.py +3 -3
- claude_mpm/services/version_control/semantic_versioning.py +13 -13
- claude_mpm/services/version_control/version_parser.py +1 -1
- claude_mpm/storage/state_storage.py +12 -13
- claude_mpm/tools/code_tree_analyzer.py +5 -5
- claude_mpm/tools/code_tree_builder.py +4 -4
- claude_mpm/tools/socketio_debug.py +1 -1
- claude_mpm/utils/agent_dependency_loader.py +4 -4
- claude_mpm/utils/common.py +2 -2
- claude_mpm/utils/config_manager.py +3 -3
- claude_mpm/utils/dependency_cache.py +2 -2
- claude_mpm/utils/dependency_strategies.py +6 -6
- claude_mpm/utils/file_utils.py +11 -11
- claude_mpm/utils/log_cleanup.py +1 -1
- claude_mpm/utils/path_operations.py +1 -1
- claude_mpm/validation/agent_validator.py +2 -2
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/RECORD +190 -190
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/top_level.txt +0 -0
@@ -143,9 +143,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
143
143
|
|
144
144
|
# Map to port range
|
145
145
|
port_range = self.port_range_end - self.port_range_start + 1
|
146
|
-
|
147
|
-
|
148
|
-
return port
|
146
|
+
return self.port_range_start + (hash_int % port_range)
|
149
147
|
|
150
148
|
def _is_port_available(self, port: int) -> bool:
|
151
149
|
"""
|
@@ -177,10 +175,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
177
175
|
Returns:
|
178
176
|
True if port is protected
|
179
177
|
"""
|
180
|
-
for start, end in self.PROTECTED_PORT_RANGES
|
181
|
-
if start <= port <= end:
|
182
|
-
return True
|
183
|
-
return False
|
178
|
+
return any(start <= port <= end for start, end in self.PROTECTED_PORT_RANGES)
|
184
179
|
|
185
180
|
def _load_project_state(self) -> Dict[str, Any]:
|
186
181
|
"""
|
@@ -191,7 +186,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
191
186
|
"""
|
192
187
|
try:
|
193
188
|
if self.state_file.exists():
|
194
|
-
with
|
189
|
+
with self.state_file.open() as f:
|
195
190
|
return json.load(f)
|
196
191
|
except Exception as e:
|
197
192
|
self.log_warning(f"Failed to load project state: {e}")
|
@@ -208,7 +203,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
208
203
|
try:
|
209
204
|
# Write to temporary file first
|
210
205
|
temp_file = self.state_file.with_suffix(".tmp")
|
211
|
-
with open(
|
206
|
+
with temp_file.open("w") as f:
|
212
207
|
json.dump(state, f, indent=2)
|
213
208
|
|
214
209
|
# Atomic rename
|
@@ -227,7 +222,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
227
222
|
"""
|
228
223
|
try:
|
229
224
|
if self.global_registry_file.exists():
|
230
|
-
with
|
225
|
+
with self.global_registry_file.open() as f:
|
231
226
|
return json.load(f)
|
232
227
|
except Exception as e:
|
233
228
|
self.log_warning(f"Failed to load global registry: {e}")
|
@@ -247,7 +242,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
247
242
|
|
248
243
|
# Write to temporary file first
|
249
244
|
temp_file = self.global_registry_file.with_suffix(".tmp")
|
250
|
-
with open(
|
245
|
+
with temp_file.open("w") as f:
|
251
246
|
json.dump(registry, f, indent=2)
|
252
247
|
|
253
248
|
# Atomic rename
|
@@ -507,7 +502,7 @@ class ProjectPortAllocator(SyncBaseService):
|
|
507
502
|
state_file = project_path / ".claude-mpm" / self.STATE_FILE_NAME
|
508
503
|
if state_file.exists():
|
509
504
|
try:
|
510
|
-
with open(
|
505
|
+
with state_file.open() as f:
|
511
506
|
project_state = json.load(f)
|
512
507
|
|
513
508
|
# Check if service still registered
|
@@ -187,7 +187,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
187
187
|
event_data["timestamp"] = datetime.now(timezone.utc).isoformat()
|
188
188
|
|
189
189
|
# Append to log file as JSONL
|
190
|
-
with open(
|
190
|
+
with log_file.open("a") as f:
|
191
191
|
f.write(json.dumps(event_data) + "\n")
|
192
192
|
|
193
193
|
except Exception as e:
|
@@ -342,7 +342,7 @@ class EventNormalizer:
|
|
342
342
|
|
343
343
|
return "unknown"
|
344
344
|
|
345
|
-
def _map_event_name(self, event_name: str) -> Tuple[str, str]:
|
345
|
+
def _map_event_name(self, event_name: str) -> Tuple[str, str]:
|
346
346
|
"""Map event name to (type, subtype) tuple.
|
347
347
|
|
348
348
|
WHY: Consistent categorization helps clients filter and handle events.
|
@@ -41,6 +41,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
41
41
|
self.logger = get_logger(__name__)
|
42
42
|
self.analysis_runner = None
|
43
43
|
self.code_analyzer = None # For lazy loading operations
|
44
|
+
self._emit_tasks: set = set() # Track emit tasks to prevent GC
|
45
|
+
|
46
|
+
def _create_emit_task(self, coro):
|
47
|
+
"""Create a tracked emit task to prevent garbage collection."""
|
48
|
+
task = asyncio.get_event_loop().create_task(coro)
|
49
|
+
self._emit_tasks.add(task)
|
50
|
+
task.add_done_callback(self._emit_tasks.discard)
|
51
|
+
return task
|
44
52
|
|
45
53
|
def initialize(self):
|
46
54
|
"""Initialize the analysis runner."""
|
@@ -246,16 +254,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
246
254
|
# Special handling for 'info' events - they should be passed through directly
|
247
255
|
if event_type == "info":
|
248
256
|
# INFO events for granular tracking
|
249
|
-
|
250
|
-
loop.create_task(
|
257
|
+
self._create_emit_task(
|
251
258
|
self.server.core.sio.emit(
|
252
259
|
"info", {"request_id": request_id, **event_data}
|
253
260
|
)
|
254
261
|
)
|
255
262
|
else:
|
256
263
|
# Regular code analysis events
|
257
|
-
|
258
|
-
loop.create_task(
|
264
|
+
self._create_emit_task(
|
259
265
|
self.server.core.sio.emit(
|
260
266
|
event_type, {"request_id": request_id, **event_data}
|
261
267
|
)
|
@@ -437,16 +443,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
437
443
|
# Special handling for 'info' events - they should be passed through directly
|
438
444
|
if event_type == "info":
|
439
445
|
# INFO events for granular tracking
|
440
|
-
|
441
|
-
loop.create_task(
|
446
|
+
self._create_emit_task(
|
442
447
|
self.server.core.sio.emit(
|
443
448
|
"info", {"request_id": request_id, **event_data}
|
444
449
|
)
|
445
450
|
)
|
446
451
|
else:
|
447
452
|
# Regular code analysis events
|
448
|
-
|
449
|
-
loop.create_task(
|
453
|
+
self._create_emit_task(
|
450
454
|
self.server.core.sio.emit(
|
451
455
|
event_type, {"request_id": request_id, **event_data}
|
452
456
|
)
|
@@ -609,16 +613,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
609
613
|
# Special handling for 'info' events - they should be passed through directly
|
610
614
|
if event_type == "info":
|
611
615
|
# INFO events for granular tracking
|
612
|
-
|
613
|
-
loop.create_task(
|
616
|
+
self._create_emit_task(
|
614
617
|
self.server.core.sio.emit(
|
615
618
|
"info", {"request_id": request_id, **event_data}
|
616
619
|
)
|
617
620
|
)
|
618
621
|
else:
|
619
622
|
# Regular code analysis events
|
620
|
-
|
621
|
-
loop.create_task(
|
623
|
+
self._create_emit_task(
|
622
624
|
self.server.core.sio.emit(
|
623
625
|
event_type, {"request_id": request_id, **event_data}
|
624
626
|
)
|
@@ -224,7 +224,7 @@ class FileEventHandler(BaseEventHandler):
|
|
224
224
|
be displayed as text.
|
225
225
|
"""
|
226
226
|
try:
|
227
|
-
with open(
|
227
|
+
with real_path.open("rb") as f:
|
228
228
|
binary_content = f.read()
|
229
229
|
|
230
230
|
# Check if it's a text file by looking for common text patterns
|
@@ -223,7 +223,7 @@ class EventTypeMapper:
|
|
223
223
|
}
|
224
224
|
|
225
225
|
@classmethod
|
226
|
-
def map_event_type(cls, old_type: str) -> Tuple[str, str]:
|
226
|
+
def map_event_type(cls, old_type: str) -> Tuple[str, str]:
|
227
227
|
"""Map an old event type to new type/subtype.
|
228
228
|
|
229
229
|
WHY: Provides consistent categorization for all events.
|
@@ -428,7 +428,7 @@ class SocketIOServerCore:
|
|
428
428
|
)
|
429
429
|
|
430
430
|
# Add file reading endpoint for source viewer
|
431
|
-
async def file_read_handler(request):
|
431
|
+
async def file_read_handler(request):
|
432
432
|
"""Handle GET /api/file/read for reading source files."""
|
433
433
|
import os
|
434
434
|
|
@@ -305,7 +305,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
|
|
305
305
|
tree = ast.parse(content)
|
306
306
|
complexity["cyclomatic"] = self._calculate_cyclomatic_complexity(tree)
|
307
307
|
complexity["cognitive"] = self._calculate_cognitive_complexity(tree)
|
308
|
-
except:
|
308
|
+
except (SyntaxError, ValueError):
|
309
309
|
pass
|
310
310
|
|
311
311
|
return complexity
|
@@ -372,7 +372,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
372
372
|
def _parse_package_json(self, path: Path) -> Dict[str, Any]:
|
373
373
|
"""Parse package.json file."""
|
374
374
|
try:
|
375
|
-
with open(
|
375
|
+
with path.open() as f:
|
376
376
|
data = json.load(f)
|
377
377
|
|
378
378
|
return {
|
@@ -417,7 +417,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
417
417
|
return {}
|
418
418
|
|
419
419
|
try:
|
420
|
-
with open(
|
420
|
+
with path.open("rb") as f:
|
421
421
|
data = tomllib.load(f)
|
422
422
|
|
423
423
|
dependencies = {}
|
@@ -459,7 +459,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
459
459
|
return {}
|
460
460
|
|
461
461
|
try:
|
462
|
-
with open(
|
462
|
+
with path.open("rb") as f:
|
463
463
|
data = tomllib.load(f)
|
464
464
|
|
465
465
|
return {
|
@@ -481,7 +481,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
481
481
|
return {}
|
482
482
|
|
483
483
|
try:
|
484
|
-
with open(
|
484
|
+
with path.open("rb") as f:
|
485
485
|
data = tomllib.load(f)
|
486
486
|
|
487
487
|
return {
|
@@ -471,7 +471,7 @@ class SchemaValidator:
|
|
471
471
|
try:
|
472
472
|
datetime.strptime(value, format)
|
473
473
|
return True
|
474
|
-
except:
|
474
|
+
except (ValueError, TypeError):
|
475
475
|
return False
|
476
476
|
|
477
477
|
def _validate_uuid(self, value: str) -> bool:
|
@@ -481,7 +481,7 @@ class SchemaValidator:
|
|
481
481
|
try:
|
482
482
|
uuid.UUID(value)
|
483
483
|
return True
|
484
|
-
except:
|
484
|
+
except (ValueError, TypeError, AttributeError):
|
485
485
|
return False
|
486
486
|
|
487
487
|
def _validate_ipv4(self, value: str) -> bool:
|
@@ -491,7 +491,7 @@ class SchemaValidator:
|
|
491
491
|
try:
|
492
492
|
ipaddress.IPv4Address(value)
|
493
493
|
return True
|
494
|
-
except:
|
494
|
+
except (ValueError, TypeError, ipaddress.AddressValueError):
|
495
495
|
return False
|
496
496
|
|
497
497
|
def _validate_ipv6(self, value: str) -> bool:
|
@@ -501,7 +501,7 @@ class SchemaValidator:
|
|
501
501
|
try:
|
502
502
|
ipaddress.IPv6Address(value)
|
503
503
|
return True
|
504
|
-
except:
|
504
|
+
except (ValueError, TypeError, ipaddress.AddressValueError):
|
505
505
|
return False
|
506
506
|
|
507
507
|
def _validate_semver(self, value: str) -> bool:
|
@@ -9,7 +9,7 @@ from abc import ABC, abstractmethod
|
|
9
9
|
from collections import OrderedDict
|
10
10
|
from contextlib import contextmanager
|
11
11
|
from dataclasses import dataclass, field
|
12
|
-
from datetime import datetime, timedelta
|
12
|
+
from datetime import datetime, timedelta, timezone
|
13
13
|
from enum import Enum
|
14
14
|
from pathlib import Path
|
15
15
|
from typing import Any, Callable, Dict, List, Optional, Set, Union
|
@@ -124,11 +124,11 @@ class HierarchicalContextManager(BaseContextManager):
|
|
124
124
|
id=context_id,
|
125
125
|
scope=scope,
|
126
126
|
lifecycle=ContextLifecycle.CREATED,
|
127
|
-
created_at=datetime.now(),
|
128
|
-
updated_at=datetime.now(),
|
127
|
+
created_at=datetime.now(timezone.utc),
|
128
|
+
updated_at=datetime.now(timezone.utc),
|
129
129
|
parent_id=parent_id,
|
130
130
|
ttl=ttl,
|
131
|
-
expires_at=datetime.now() + ttl if ttl else None,
|
131
|
+
expires_at=datetime.now(timezone.utc) + ttl if ttl else None,
|
132
132
|
attributes=kwargs,
|
133
133
|
)
|
134
134
|
|
@@ -158,7 +158,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
158
158
|
|
159
159
|
# Check expiration
|
160
160
|
if context and context.expires_at:
|
161
|
-
if datetime.now() > context.expires_at:
|
161
|
+
if datetime.now(timezone.utc) > context.expires_at:
|
162
162
|
self.close_context(context_id)
|
163
163
|
return None
|
164
164
|
|
@@ -299,7 +299,9 @@ class ScopedConfigManager:
|
|
299
299
|
|
300
300
|
# Update context metadata
|
301
301
|
if context_id in self.context_manager.contexts:
|
302
|
-
self.context_manager.contexts[context_id].updated_at = datetime.now(
|
302
|
+
self.context_manager.contexts[context_id].updated_at = datetime.now(
|
303
|
+
timezone.utc
|
304
|
+
)
|
303
305
|
|
304
306
|
def _get_inherited_config(self, context_id: str) -> Dict[str, Any]:
|
305
307
|
"""Get merged configuration from context hierarchy"""
|
@@ -206,7 +206,7 @@ class FileIOErrorHandler(BaseErrorHandler):
|
|
206
206
|
result.fallback_value = str(alt_path)
|
207
207
|
result.actions_taken.append(f"Using alternative location: {alt_path}")
|
208
208
|
|
209
|
-
except:
|
209
|
+
except (OSError, PermissionError):
|
210
210
|
result.should_escalate = True
|
211
211
|
|
212
212
|
# Use read-only mode if applicable
|
@@ -293,7 +293,7 @@ class ParsingErrorHandler(BaseErrorHandler):
|
|
293
293
|
result.actions_taken.append(f"Fixed JSON with {fix_func.__name__}")
|
294
294
|
self.logger.info(f"Recovered from JSON error using {fix_func.__name__}")
|
295
295
|
return result
|
296
|
-
except:
|
296
|
+
except (json.JSONDecodeError, ValueError, TypeError):
|
297
297
|
continue
|
298
298
|
|
299
299
|
# Use lenient parser if available
|
@@ -346,7 +346,7 @@ class ParsingErrorHandler(BaseErrorHandler):
|
|
346
346
|
result.recovered = True
|
347
347
|
result.fallback_value = parsed
|
348
348
|
result.actions_taken.append("Parsed as Python literal")
|
349
|
-
except:
|
349
|
+
except (ValueError, SyntaxError, TypeError):
|
350
350
|
# Return empty dict as last resort
|
351
351
|
result.recovered = True
|
352
352
|
result.fallback_value = {}
|
@@ -370,7 +370,7 @@ class ParsingErrorHandler(BaseErrorHandler):
|
|
370
370
|
result.fallback_value = parsed
|
371
371
|
result.actions_taken.append("Parsed with safe YAML loader")
|
372
372
|
|
373
|
-
except:
|
373
|
+
except (yaml.YAMLError, ValueError, AttributeError):
|
374
374
|
# Try to fix tabs
|
375
375
|
content = content.replace("\t", " ")
|
376
376
|
try:
|
@@ -378,7 +378,7 @@ class ParsingErrorHandler(BaseErrorHandler):
|
|
378
378
|
result.recovered = True
|
379
379
|
result.fallback_value = parsed
|
380
380
|
result.actions_taken.append("Fixed YAML tabs")
|
381
|
-
except:
|
381
|
+
except (yaml.YAMLError, ValueError, AttributeError):
|
382
382
|
result.fallback_value = {}
|
383
383
|
result.actions_taken.append("Used empty configuration as fallback")
|
384
384
|
|
@@ -406,7 +406,7 @@ class ParsingErrorHandler(BaseErrorHandler):
|
|
406
406
|
result.fallback_value = parsed
|
407
407
|
result.actions_taken.append(f"Parsed as {format_name}")
|
408
408
|
return result
|
409
|
-
except:
|
409
|
+
except (ValueError, TypeError, AttributeError, ImportError):
|
410
410
|
continue
|
411
411
|
|
412
412
|
# Use default/empty config
|
@@ -533,7 +533,7 @@ class ValidationErrorHandler(BaseErrorHandler):
|
|
533
533
|
if isinstance(value, str):
|
534
534
|
return json.loads(value)
|
535
535
|
return dict(value)
|
536
|
-
except:
|
536
|
+
except (ValueError, TypeError, json.JSONDecodeError):
|
537
537
|
return None
|
538
538
|
|
539
539
|
def _handle_generic_validation(
|
@@ -661,7 +661,7 @@ class TypeConversionErrorHandler(BaseErrorHandler):
|
|
661
661
|
if converter:
|
662
662
|
try:
|
663
663
|
return converter(value)
|
664
|
-
except:
|
664
|
+
except (ValueError, TypeError, AttributeError):
|
665
665
|
pass
|
666
666
|
|
667
667
|
return None
|
@@ -706,7 +706,7 @@ class TypeConversionErrorHandler(BaseErrorHandler):
|
|
706
706
|
if value.startswith("["):
|
707
707
|
try:
|
708
708
|
return json.loads(value)
|
709
|
-
except:
|
709
|
+
except (json.JSONDecodeError, ValueError):
|
710
710
|
pass
|
711
711
|
# Try comma-separated
|
712
712
|
return [v.strip() for v in value.split(",")]
|
@@ -720,7 +720,7 @@ class TypeConversionErrorHandler(BaseErrorHandler):
|
|
720
720
|
# Try JSON object
|
721
721
|
try:
|
722
722
|
return json.loads(value)
|
723
|
-
except:
|
723
|
+
except (json.JSONDecodeError, ValueError):
|
724
724
|
pass
|
725
725
|
# Try key=value pairs
|
726
726
|
result = {}
|
@@ -75,7 +75,7 @@ class BaseFileLoader(ABC):
|
|
75
75
|
f"Read {path} with fallback encoding: {enc}"
|
76
76
|
)
|
77
77
|
return f.read()
|
78
|
-
except:
|
78
|
+
except (UnicodeDecodeError, OSError):
|
79
79
|
continue
|
80
80
|
raise
|
81
81
|
|
@@ -185,8 +185,8 @@ class StructuredFileLoader(BaseFileLoader):
|
|
185
185
|
import tomli
|
186
186
|
|
187
187
|
return tomli.loads(content)
|
188
|
-
except ImportError:
|
189
|
-
raise ImportError("Neither toml nor tomli package is installed")
|
188
|
+
except ImportError as e:
|
189
|
+
raise ImportError("Neither toml nor tomli package is installed") from e
|
190
190
|
except Exception as e:
|
191
191
|
if context.strict:
|
192
192
|
raise
|
@@ -209,7 +209,7 @@ class StructuredFileLoader(BaseFileLoader):
|
|
209
209
|
|
210
210
|
try:
|
211
211
|
return json.loads(content)
|
212
|
-
except:
|
212
|
+
except (json.JSONDecodeError, ValueError):
|
213
213
|
return {}
|
214
214
|
|
215
215
|
def _process_includes(
|
@@ -411,7 +411,7 @@ class EnvironmentFileLoader(BaseFileLoader):
|
|
411
411
|
if value.startswith(("[", "{")):
|
412
412
|
try:
|
413
413
|
return json.loads(value)
|
414
|
-
except:
|
414
|
+
except (json.JSONDecodeError, ValueError):
|
415
415
|
pass
|
416
416
|
|
417
417
|
# Comma-separated list
|
@@ -12,7 +12,7 @@ import threading
|
|
12
12
|
from abc import ABC, abstractmethod
|
13
13
|
from collections import defaultdict
|
14
14
|
from dataclasses import dataclass, field
|
15
|
-
from datetime import datetime, timedelta
|
15
|
+
from datetime import datetime, timedelta, timezone
|
16
16
|
from enum import Enum
|
17
17
|
from pathlib import Path
|
18
18
|
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
|
@@ -216,7 +216,7 @@ class UnifiedConfigService:
|
|
216
216
|
source=str(source),
|
217
217
|
format=format,
|
218
218
|
context=context,
|
219
|
-
loaded_at=datetime.now(),
|
219
|
+
loaded_at=datetime.now(timezone.utc),
|
220
220
|
checksum=self._calculate_checksum(config),
|
221
221
|
hot_reload=hot_reload,
|
222
222
|
ttl=ttl,
|
@@ -439,7 +439,7 @@ class UnifiedConfigService:
|
|
439
439
|
|
440
440
|
path = Path(source)
|
441
441
|
if path.exists():
|
442
|
-
with open(
|
442
|
+
with path.open() as f:
|
443
443
|
return json.load(f)
|
444
444
|
|
445
445
|
# Try to parse as JSON string
|
@@ -452,7 +452,7 @@ class UnifiedConfigService:
|
|
452
452
|
|
453
453
|
path = Path(source)
|
454
454
|
if path.exists():
|
455
|
-
with open(
|
455
|
+
with path.open() as f:
|
456
456
|
return yaml.safe_load(f)
|
457
457
|
|
458
458
|
# Try to parse as YAML string
|
@@ -476,7 +476,7 @@ class UnifiedConfigService:
|
|
476
476
|
# Try to parse value
|
477
477
|
try:
|
478
478
|
config[clean_key] = json.loads(value)
|
479
|
-
except:
|
479
|
+
except (json.JSONDecodeError, ValueError):
|
480
480
|
config[clean_key] = value
|
481
481
|
|
482
482
|
return config
|
@@ -508,7 +508,7 @@ class UnifiedConfigService:
|
|
508
508
|
|
509
509
|
path = Path(source)
|
510
510
|
if path.exists():
|
511
|
-
with open(
|
511
|
+
with path.open() as f:
|
512
512
|
return toml.load(f)
|
513
513
|
|
514
514
|
return toml.loads(str(source))
|
@@ -706,7 +706,7 @@ class UnifiedConfigService:
|
|
706
706
|
"""Check if cached configuration is still valid"""
|
707
707
|
if metadata.ttl:
|
708
708
|
expiry = metadata.loaded_at + metadata.ttl
|
709
|
-
if datetime.now() > expiry:
|
709
|
+
if datetime.now(timezone.utc) > expiry:
|
710
710
|
return False
|
711
711
|
return True
|
712
712
|
|
@@ -742,7 +742,7 @@ class UnifiedConfigService:
|
|
742
742
|
result = handler(error, source, context)
|
743
743
|
if result is not None:
|
744
744
|
return result
|
745
|
-
except:
|
745
|
+
except Exception:
|
746
746
|
continue
|
747
747
|
|
748
748
|
self.logger.error(f"Failed to load config from {source}: {error}")
|
@@ -402,7 +402,7 @@ class FormatValidator(BaseValidator):
|
|
402
402
|
try:
|
403
403
|
result = urllib.parse.urlparse(value)
|
404
404
|
return all([result.scheme, result.netloc])
|
405
|
-
except:
|
405
|
+
except (ValueError, AttributeError, TypeError):
|
406
406
|
return False
|
407
407
|
|
408
408
|
@staticmethod
|
@@ -410,7 +410,7 @@ class FormatValidator(BaseValidator):
|
|
410
410
|
try:
|
411
411
|
result = urllib.parse.urlparse(value)
|
412
412
|
return bool(result.scheme)
|
413
|
-
except:
|
413
|
+
except (ValueError, AttributeError, TypeError):
|
414
414
|
return False
|
415
415
|
|
416
416
|
@staticmethod
|
@@ -420,7 +420,7 @@ class FormatValidator(BaseValidator):
|
|
420
420
|
try:
|
421
421
|
uuid.UUID(value)
|
422
422
|
return True
|
423
|
-
except:
|
423
|
+
except (ValueError, AttributeError, TypeError):
|
424
424
|
return False
|
425
425
|
|
426
426
|
@staticmethod
|
@@ -428,7 +428,7 @@ class FormatValidator(BaseValidator):
|
|
428
428
|
try:
|
429
429
|
ipaddress.IPv4Address(value)
|
430
430
|
return True
|
431
|
-
except:
|
431
|
+
except (ValueError, ipaddress.AddressValueError):
|
432
432
|
return False
|
433
433
|
|
434
434
|
@staticmethod
|
@@ -436,7 +436,7 @@ class FormatValidator(BaseValidator):
|
|
436
436
|
try:
|
437
437
|
ipaddress.IPv6Address(value)
|
438
438
|
return True
|
439
|
-
except:
|
439
|
+
except (ValueError, ipaddress.AddressValueError):
|
440
440
|
return False
|
441
441
|
|
442
442
|
@staticmethod
|
@@ -444,7 +444,7 @@ class FormatValidator(BaseValidator):
|
|
444
444
|
try:
|
445
445
|
ipaddress.ip_address(value)
|
446
446
|
return True
|
447
|
-
except:
|
447
|
+
except (ValueError, ipaddress.AddressValueError):
|
448
448
|
return False
|
449
449
|
|
450
450
|
@staticmethod
|
@@ -461,7 +461,7 @@ class FormatValidator(BaseValidator):
|
|
461
461
|
try:
|
462
462
|
datetime.strptime(value, "%Y-%m-%d")
|
463
463
|
return True
|
464
|
-
except:
|
464
|
+
except (ValueError, TypeError):
|
465
465
|
return False
|
466
466
|
|
467
467
|
@staticmethod
|
@@ -469,11 +469,11 @@ class FormatValidator(BaseValidator):
|
|
469
469
|
try:
|
470
470
|
datetime.strptime(value, "%H:%M:%S")
|
471
471
|
return True
|
472
|
-
except:
|
472
|
+
except (ValueError, TypeError):
|
473
473
|
try:
|
474
474
|
datetime.strptime(value, "%H:%M")
|
475
475
|
return True
|
476
|
-
except:
|
476
|
+
except (ValueError, TypeError):
|
477
477
|
return False
|
478
478
|
|
479
479
|
@staticmethod
|
@@ -488,7 +488,7 @@ class FormatValidator(BaseValidator):
|
|
488
488
|
try:
|
489
489
|
datetime.strptime(value, fmt)
|
490
490
|
return True
|
491
|
-
except:
|
491
|
+
except (ValueError, TypeError):
|
492
492
|
continue
|
493
493
|
return False
|
494
494
|
|
@@ -499,7 +499,7 @@ class FormatValidator(BaseValidator):
|
|
499
499
|
try:
|
500
500
|
json.loads(value)
|
501
501
|
return True
|
502
|
-
except:
|
502
|
+
except (json.JSONDecodeError, ValueError, TypeError):
|
503
503
|
return False
|
504
504
|
|
505
505
|
@staticmethod
|
@@ -509,7 +509,7 @@ class FormatValidator(BaseValidator):
|
|
509
509
|
try:
|
510
510
|
base64.b64decode(value, validate=True)
|
511
511
|
return True
|
512
|
-
except:
|
512
|
+
except (ValueError, base64.binascii.Error):
|
513
513
|
return False
|
514
514
|
|
515
515
|
@staticmethod
|
@@ -517,7 +517,7 @@ class FormatValidator(BaseValidator):
|
|
517
517
|
try:
|
518
518
|
Path(value)
|
519
519
|
return True
|
520
|
-
except:
|
520
|
+
except (ValueError, TypeError, OSError):
|
521
521
|
return False
|
522
522
|
|
523
523
|
@staticmethod
|
@@ -709,7 +709,7 @@ class ConditionalValidator(BaseValidator):
|
|
709
709
|
|
710
710
|
try:
|
711
711
|
return comparator(actual, expected)
|
712
|
-
except:
|
712
|
+
except (TypeError, ValueError, AttributeError, KeyError):
|
713
713
|
return False
|
714
714
|
|
715
715
|
def _apply_rule(
|
@@ -910,7 +910,7 @@ class CrossFieldValidator(BaseValidator):
|
|
910
910
|
if comparator:
|
911
911
|
try:
|
912
912
|
return comparator(val1, val2)
|
913
|
-
except:
|
913
|
+
except (TypeError, ValueError, AttributeError, KeyError):
|
914
914
|
return False
|
915
915
|
|
916
916
|
return False
|