Skip to content

Commit 3cdd026

Browse files
🤖 Plandex → Enhance dependency management and installation scripts to fully support sub-dependencies with improved validation, error handling, and FreeCAD integration testing
1 parent 6eff07c commit 3cdd026

File tree

3 files changed

+57
-71
lines changed

3 files changed

+57
-71
lines changed

freecad-ai/ai/providers/__init__.py

Lines changed: 48 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,56 +26,56 @@
2626
def _attempt_dependency_installation():
2727
"""Attempt to install missing dependencies automatically."""
2828
global _dependency_install_attempted
29-
29+
3030
if _dependency_install_attempted:
3131
return False # Don't try multiple times
32-
32+
3333
_dependency_install_attempted = True
34-
34+
3535
try:
3636
FreeCAD.Console.PrintMessage("FreeCAD AI: Attempting automatic dependency installation...\n")
37-
37+
3838
# Try to import and use the dependency manager
3939
try:
4040
from utils.dependency_manager import DependencyManager
41-
41+
4242
def progress_callback(message):
4343
FreeCAD.Console.PrintMessage(f"FreeCAD AI: {message}\n")
44-
44+
4545
manager = DependencyManager(progress_callback)
46-
46+
4747
# Check for missing critical dependencies and sub-dependencies
4848
critical_missing = manager.get_critical_missing_dependencies()
49-
49+
5050
if critical_missing:
5151
FreeCAD.Console.PrintMessage(f"FreeCAD AI: Installing critical dependencies: {', '.join(critical_missing)}\n")
52-
52+
5353
# Special handling for aiohttp and its sub-dependencies
5454
if "aiohttp" in critical_missing:
5555
FreeCAD.Console.PrintMessage("FreeCAD AI: Checking aiohttp sub-dependencies...\n")
56-
56+
5757
# Check sub-dependencies
5858
sub_deps = manager.check_sub_dependencies("aiohttp")
5959
missing_sub_deps = [dep for dep, available in sub_deps.items() if not available]
60-
60+
6161
if missing_sub_deps:
6262
FreeCAD.Console.PrintMessage(f"FreeCAD AI: Missing sub-dependencies: {', '.join(missing_sub_deps)}\n")
63-
63+
6464
# Try to install critical dependencies with sub-dependency support
6565
success = manager.install_missing_dependencies(critical_only=True)
66-
66+
6767
if success:
6868
FreeCAD.Console.PrintMessage("FreeCAD AI: ✅ Critical dependencies installed successfully\n")
69-
69+
7070
# Verify sub-dependencies were installed correctly
7171
if "aiohttp" in critical_missing and manager.check_dependency("aiohttp"):
7272
sub_deps_after = manager.check_sub_dependencies("aiohttp")
7373
still_missing = [dep for dep, available in sub_deps_after.items() if not available]
74-
74+
7575
if still_missing:
7676
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ⚠️ Some sub-dependencies still missing: {', '.join(still_missing)}\n")
7777
FreeCAD.Console.PrintMessage("FreeCAD AI: Attempting to install missing sub-dependencies individually...\n")
78-
78+
7979
# Try to install missing sub-dependencies individually
8080
for sub_dep in still_missing:
8181
if manager.install_dependency(sub_dep):
@@ -84,38 +84,38 @@ def progress_callback(message):
8484
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ❌ Failed to install sub-dependency {sub_dep}\n")
8585
else:
8686
FreeCAD.Console.PrintMessage("FreeCAD AI: ✅ All aiohttp sub-dependencies verified\n")
87-
87+
8888
FreeCAD.Console.PrintMessage("FreeCAD AI: Please restart FreeCAD to use the new dependencies\n")
8989
return True
9090
else:
9191
FreeCAD.Console.PrintWarning("FreeCAD AI: ❌ Failed to install some critical dependencies\n")
9292
return False
9393
else:
9494
FreeCAD.Console.PrintMessage("FreeCAD AI: All critical dependencies are already available\n")
95-
95+
9696
# Even if main dependencies are available, check sub-dependencies
9797
if manager.check_dependency("aiohttp"):
9898
sub_deps = manager.check_sub_dependencies("aiohttp")
9999
missing_sub_deps = [dep for dep, available in sub_deps.items() if not available]
100-
100+
101101
if missing_sub_deps:
102102
FreeCAD.Console.PrintMessage(f"FreeCAD AI: Installing missing aiohttp sub-dependencies: {', '.join(missing_sub_deps)}\n")
103-
103+
104104
for sub_dep in missing_sub_deps:
105105
if manager.install_dependency(sub_dep):
106106
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ✅ Sub-dependency {sub_dep} installed\n")
107107
else:
108108
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ❌ Failed to install sub-dependency {sub_dep}\n")
109-
109+
110110
return True
111-
111+
112112
except ImportError as e:
113113
FreeCAD.Console.PrintWarning(f"FreeCAD AI: Could not import dependency manager: {e}\n")
114114
return False
115115
except Exception as e:
116116
FreeCAD.Console.PrintError(f"FreeCAD AI: Dependency installation failed: {e}\n")
117117
return False
118-
118+
119119
except Exception as e:
120120
FreeCAD.Console.PrintError(f"FreeCAD AI: Automatic dependency installation error: {e}\n")
121121
return False
@@ -173,32 +173,30 @@ def _show_dependency_guidance(missing_dependency, provider_name):
173173
FreeCAD.Console.PrintMessage("=" * 60 + "\n")
174174

175175

176-
177176
def _show_sub_dependency_guidance(main_dependency, missing_sub_dependency, provider_name):
178177
"""Show user-friendly guidance for installing missing sub-dependencies."""
179178
FreeCAD.Console.PrintMessage("=" * 60 + "\n")
180179
FreeCAD.Console.PrintMessage("FreeCAD AI: SUB-DEPENDENCY INSTALLATION GUIDE\n")
181180
FreeCAD.Console.PrintMessage("=" * 60 + "\n")
182-
181+
183182
FreeCAD.Console.PrintMessage(f"The {provider_name} provider requires '{missing_sub_dependency}', which is a sub-dependency of '{main_dependency}'.\n")
184183
FreeCAD.Console.PrintMessage(f"This usually means {main_dependency} was installed without its required sub-dependencies.\n")
185-
184+
186185
FreeCAD.Console.PrintMessage("\n📋 INSTALLATION OPTIONS:\n")
187186
FreeCAD.Console.PrintMessage("\n1. 🔧 Use the FreeCAD AI Dependencies Tab:\n")
188187
FreeCAD.Console.PrintMessage(" - Open the FreeCAD AI interface\n")
189188
FreeCAD.Console.PrintMessage(" - Go to the 'Dependencies' or 'Settings' tab\n")
190189
FreeCAD.Console.PrintMessage(" - Click 'Install Missing Dependencies'\n")
191-
FreeCAD.Console.PrintMessage(" - This will install both main and sub-dependencies\n")
192-
190+
193191
FreeCAD.Console.PrintMessage("\n2. 🐍 Manual Installation via FreeCAD Python Console:\n")
194192
FreeCAD.Console.PrintMessage(" Copy and paste this into the FreeCAD Python console:\n")
195193
FreeCAD.Console.PrintMessage(" " + "-" * 50 + "\n")
196-
194+
197195
# Generate installation script for sub-dependency
198196
try:
199197
from utils.dependency_manager import DependencyManager
200198
manager = DependencyManager()
201-
199+
202200
# Create script for both main dependency and sub-dependency
203201
FreeCAD.Console.PrintMessage(" exec('''\n")
204202
FreeCAD.Console.PrintMessage(" import subprocess, sys, os\n")
@@ -214,27 +212,28 @@ def _show_sub_dependency_guidance(main_dependency, missing_sub_dependency, provi
214212
FreeCAD.Console.PrintMessage(" import subprocess, sys\n")
215213
FreeCAD.Console.PrintMessage(f" subprocess.run([sys.executable, '-m', 'pip', 'install', '{missing_sub_dependency}'])\n")
216214
FreeCAD.Console.PrintMessage(f" subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade', '{main_dependency}'])\n")
217-
215+
218216
FreeCAD.Console.PrintMessage(" " + "-" * 50 + "\n")
219-
217+
220218
FreeCAD.Console.PrintMessage("\n3. 💻 System Package Manager:\n")
221219
if main_dependency == "aiohttp":
222220
FreeCAD.Console.PrintMessage(" Ubuntu/Debian: sudo apt install python3-aiohttp python3-multidict python3-yarl\n")
223221
FreeCAD.Console.PrintMessage(" Fedora: sudo dnf install python3-aiohttp python3-multidict python3-yarl\n")
224222
FreeCAD.Console.PrintMessage(" macOS: pip3 install aiohttp[speedups]\n")
225223
else:
226224
FreeCAD.Console.PrintMessage(f" Install both: pip3 install {missing_sub_dependency} {main_dependency}\n")
227-
225+
228226
FreeCAD.Console.PrintMessage("\n4. 🔄 Restart FreeCAD:\n")
229227
FreeCAD.Console.PrintMessage(" After installation, restart FreeCAD to use the new dependencies\n")
230-
228+
231229
FreeCAD.Console.PrintMessage("\n💡 TROUBLESHOOTING:\n")
232230
FreeCAD.Console.PrintMessage(" - Sub-dependencies are often missed when using --no-deps flag\n")
233231
FreeCAD.Console.PrintMessage(" - Try reinstalling the main dependency without --no-deps\n")
234232
FreeCAD.Console.PrintMessage(" - Check that your pip version is up to date\n")
235-
233+
236234
FreeCAD.Console.PrintMessage("=" * 60 + "\n")
237235

236+
238237
def _lazy_import_provider(provider_name: str, module_name: str, class_name: str):
239238
"""Lazy import a provider with enhanced dependency management and error handling."""
240239
if provider_name in _providers:
@@ -250,15 +249,15 @@ def _lazy_import_provider(provider_name: str, module_name: str, class_name: str)
250249
_providers[provider_name] = provider_class
251250
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ✅ {provider_name} provider loaded successfully\n")
252251
return provider_class
253-
252+
254253
except ImportError as e:
255254
error_msg = f"Failed to import {provider_name}: {str(e)}"
256255
_provider_errors[provider_name] = error_msg
257-
256+
258257
# Enhanced sub-dependency detection
259258
missing_dependency = None
260259
missing_sub_dependency = None
261-
260+
262261
if "aiohttp" in str(e):
263262
missing_dependency = "aiohttp"
264263
elif "multidict" in str(e):
@@ -274,21 +273,21 @@ def _lazy_import_provider(provider_name: str, module_name: str, class_name: str)
274273
missing_dependency = "requests"
275274
elif "mcp" in str(e):
276275
missing_dependency = "mcp"
277-
276+
278277
if missing_dependency:
279278
if missing_sub_dependency:
280279
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ❌ {provider_name} provider unavailable - missing '{missing_sub_dependency}' sub-dependency\n")
281280
FreeCAD.Console.PrintWarning(f"FreeCAD AI: This is a sub-dependency of '{missing_dependency}' that wasn't installed properly\n")
282281
else:
283282
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ❌ {provider_name} provider unavailable - missing '{missing_dependency}' dependency\n")
284-
283+
285284
# Attempt automatic installation with sub-dependency handling
286285
if not _dependency_install_attempted:
287286
if missing_sub_dependency:
288287
FreeCAD.Console.PrintMessage(f"FreeCAD AI: Attempting to install {missing_dependency} with sub-dependencies...\n")
289288
else:
290289
FreeCAD.Console.PrintMessage(f"FreeCAD AI: Attempting to install {missing_dependency} automatically...\n")
291-
290+
292291
if _attempt_dependency_installation():
293292
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ✅ Dependencies installed - restart FreeCAD to use {provider_name}\n")
294293
else:
@@ -304,9 +303,9 @@ def _lazy_import_provider(provider_name: str, module_name: str, class_name: str)
304303
_show_dependency_guidance(missing_dependency, provider_name)
305304
else:
306305
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ❌ {provider_name} provider import failed: {error_msg}\n")
307-
306+
308307
return None
309-
308+
310309
except Exception as e:
311310
error_msg = f"Error loading {provider_name}: {str(e)}"
312311
_provider_errors[provider_name] = error_msg
@@ -344,24 +343,23 @@ def get_available_providers() -> Dict[str, Any]:
344343
"OpenRouter": get_openrouter_provider(),
345344
}
346345

347-
348346
# Enhanced availability summary with sub-dependency information
349347
available_count = sum(1 for p in providers.values() if p is not None)
350348
total_count = len(providers)
351349

352350
if available_count == 0:
353351
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ⚠️ No AI providers available ({available_count}/{total_count})\n")
354352
FreeCAD.Console.PrintWarning("FreeCAD AI: Install missing dependencies to enable AI providers\n")
355-
353+
356354
# Check if it's a sub-dependency issue
357355
try:
358356
from utils.dependency_manager import DependencyManager
359357
manager = DependencyManager()
360-
358+
361359
if manager.check_dependency("aiohttp"):
362360
sub_deps = manager.check_sub_dependencies("aiohttp")
363361
missing_sub_deps = [dep for dep, available in sub_deps.items() if not available]
364-
362+
365363
if missing_sub_deps:
366364
FreeCAD.Console.PrintWarning(f"FreeCAD AI: ⚠️ aiohttp is installed but missing sub-dependencies: {', '.join(missing_sub_deps)}\n")
367365
FreeCAD.Console.PrintWarning("FreeCAD AI: Use Dependencies tab to fix sub-dependency issues\n")
@@ -370,7 +368,7 @@ def get_available_providers() -> Dict[str, Any]:
370368

371369
elif available_count < total_count:
372370
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ⚠️ Partial AI provider availability ({available_count}/{total_count})\n")
373-
371+
374372
# Show which providers are missing and why
375373
for provider_name, provider_class in providers.items():
376374
if provider_class is None and provider_name in _provider_errors:
@@ -379,10 +377,9 @@ def get_available_providers() -> Dict[str, Any]:
379377
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ⚠️ {provider_name}: Missing sub-dependency\n")
380378
else:
381379
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ⚠️ {provider_name}: Missing main dependency\n")
382-
383380
else:
384381
FreeCAD.Console.PrintMessage(f"FreeCAD AI: ✅ All AI providers available ({available_count}/{total_count})\n")
385-
382+
386383
return providers
387384

388385

@@ -407,7 +404,7 @@ def check_dependencies() -> Dict[str, bool]:
407404
# Try to use the enhanced dependency manager
408405

409406
from utils.dependency_manager import check_dependencies as enhanced_check
410-
407+
411408
dependencies = enhanced_check()
412409

413410
# Log dependency status
@@ -444,7 +441,6 @@ def install_missing_dependencies():
444441
# Try to use the dependency manager
445442

446443
from utils.dependency_manager import auto_install_dependencies
447-
448444

449445
def progress_callback(message):
450446
FreeCAD.Console.PrintMessage(f"FreeCAD AI: {message}\n")

freecad-ai/install_dependencies.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,14 @@ def install_mcp_dependencies():
165165
"--disable-pip-version-check",
166166
"--target",
167167
vendor_path,
168-
"--upgrade", # Ensure latest compatible version
168+
"--upgrade",
169169
]
170170

171171
# Add Python 3.13+ specific options
172172
if python_version >= (3, 13):
173173
cmd.extend(["--use-feature", "2020-resolver"])
174174
if package_name in ["aiohttp", "multidict", "yarl", "aiosignal"]:
175-
cmd.append("--pre") # Allow pre-releases if needed
175+
cmd.append("--pre")
176176

177177
cmd.append(package_spec)
178178

@@ -195,7 +195,7 @@ def install_mcp_dependencies():
195195
success_count += 1
196196
except ImportError:
197197
print(f" ⚠️ {package_name} installed but not importable - may need restart")
198-
success_count += 1 # Still count as success, restart may be needed
198+
success_count += 1
199199
else:
200200
print(f" ❌ Failed to install {package_name}")
201201
if result.stderr:
@@ -214,8 +214,7 @@ def install_mcp_dependencies():
214214
"--disable-pip-version-check",
215215
"--target",
216216
vendor_path,
217-
# NOTE: Removed --no-deps to allow sub-dependencies to install
218-
package_name # No version specification
217+
package_name
219218
]
220219

221220
alt_result = subprocess.run(
@@ -248,7 +247,6 @@ def install_mcp_dependencies():
248247

249248
print("\n" + "=" * 60)
250249

251-
252250
# Enhanced results reporting with sub-dependency verification
253251
if success_count == len(dependencies):
254252
print("🎉 All dependencies installed successfully!")
@@ -321,8 +319,6 @@ def install_mcp_dependencies():
321319
print(" - Avoid using --no-deps flag which skips sub-dependencies")
322320
print(" - Consider using a virtual environment with compatible package versions")
323321
print(" - Check package documentation for Python 3.13 support status")
324-
325-
326322
except Exception as e:
327323
print(f"❌ Unexpected error: {str(e)}")
328324
print("💡 Please report this error to the addon developers")

0 commit comments

Comments
 (0)