mcli-framework 7.0.0__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.

Potentially problematic release.


This version of mcli-framework might be problematic. Click here for more details.

Files changed (186) hide show
  1. mcli/app/chat_cmd.py +42 -0
  2. mcli/app/commands_cmd.py +226 -0
  3. mcli/app/completion_cmd.py +216 -0
  4. mcli/app/completion_helpers.py +288 -0
  5. mcli/app/cron_test_cmd.py +697 -0
  6. mcli/app/logs_cmd.py +419 -0
  7. mcli/app/main.py +492 -0
  8. mcli/app/model/model.py +1060 -0
  9. mcli/app/model_cmd.py +227 -0
  10. mcli/app/redis_cmd.py +269 -0
  11. mcli/app/video/video.py +1114 -0
  12. mcli/app/visual_cmd.py +303 -0
  13. mcli/chat/chat.py +2409 -0
  14. mcli/chat/command_rag.py +514 -0
  15. mcli/chat/enhanced_chat.py +652 -0
  16. mcli/chat/system_controller.py +1010 -0
  17. mcli/chat/system_integration.py +1016 -0
  18. mcli/cli.py +25 -0
  19. mcli/config.toml +20 -0
  20. mcli/lib/api/api.py +586 -0
  21. mcli/lib/api/daemon_client.py +203 -0
  22. mcli/lib/api/daemon_client_local.py +44 -0
  23. mcli/lib/api/daemon_decorator.py +217 -0
  24. mcli/lib/api/mcli_decorators.py +1032 -0
  25. mcli/lib/auth/auth.py +85 -0
  26. mcli/lib/auth/aws_manager.py +85 -0
  27. mcli/lib/auth/azure_manager.py +91 -0
  28. mcli/lib/auth/credential_manager.py +192 -0
  29. mcli/lib/auth/gcp_manager.py +93 -0
  30. mcli/lib/auth/key_manager.py +117 -0
  31. mcli/lib/auth/mcli_manager.py +93 -0
  32. mcli/lib/auth/token_manager.py +75 -0
  33. mcli/lib/auth/token_util.py +1011 -0
  34. mcli/lib/config/config.py +47 -0
  35. mcli/lib/discovery/__init__.py +1 -0
  36. mcli/lib/discovery/command_discovery.py +274 -0
  37. mcli/lib/erd/erd.py +1345 -0
  38. mcli/lib/erd/generate_graph.py +453 -0
  39. mcli/lib/files/files.py +76 -0
  40. mcli/lib/fs/fs.py +109 -0
  41. mcli/lib/lib.py +29 -0
  42. mcli/lib/logger/logger.py +611 -0
  43. mcli/lib/performance/optimizer.py +409 -0
  44. mcli/lib/performance/rust_bridge.py +502 -0
  45. mcli/lib/performance/uvloop_config.py +154 -0
  46. mcli/lib/pickles/pickles.py +50 -0
  47. mcli/lib/search/cached_vectorizer.py +479 -0
  48. mcli/lib/services/data_pipeline.py +460 -0
  49. mcli/lib/services/lsh_client.py +441 -0
  50. mcli/lib/services/redis_service.py +387 -0
  51. mcli/lib/shell/shell.py +137 -0
  52. mcli/lib/toml/toml.py +33 -0
  53. mcli/lib/ui/styling.py +47 -0
  54. mcli/lib/ui/visual_effects.py +634 -0
  55. mcli/lib/watcher/watcher.py +185 -0
  56. mcli/ml/api/app.py +215 -0
  57. mcli/ml/api/middleware.py +224 -0
  58. mcli/ml/api/routers/admin_router.py +12 -0
  59. mcli/ml/api/routers/auth_router.py +244 -0
  60. mcli/ml/api/routers/backtest_router.py +12 -0
  61. mcli/ml/api/routers/data_router.py +12 -0
  62. mcli/ml/api/routers/model_router.py +302 -0
  63. mcli/ml/api/routers/monitoring_router.py +12 -0
  64. mcli/ml/api/routers/portfolio_router.py +12 -0
  65. mcli/ml/api/routers/prediction_router.py +267 -0
  66. mcli/ml/api/routers/trade_router.py +12 -0
  67. mcli/ml/api/routers/websocket_router.py +76 -0
  68. mcli/ml/api/schemas.py +64 -0
  69. mcli/ml/auth/auth_manager.py +425 -0
  70. mcli/ml/auth/models.py +154 -0
  71. mcli/ml/auth/permissions.py +302 -0
  72. mcli/ml/backtesting/backtest_engine.py +502 -0
  73. mcli/ml/backtesting/performance_metrics.py +393 -0
  74. mcli/ml/cache.py +400 -0
  75. mcli/ml/cli/main.py +398 -0
  76. mcli/ml/config/settings.py +394 -0
  77. mcli/ml/configs/dvc_config.py +230 -0
  78. mcli/ml/configs/mlflow_config.py +131 -0
  79. mcli/ml/configs/mlops_manager.py +293 -0
  80. mcli/ml/dashboard/app.py +532 -0
  81. mcli/ml/dashboard/app_integrated.py +738 -0
  82. mcli/ml/dashboard/app_supabase.py +560 -0
  83. mcli/ml/dashboard/app_training.py +615 -0
  84. mcli/ml/dashboard/cli.py +51 -0
  85. mcli/ml/data_ingestion/api_connectors.py +501 -0
  86. mcli/ml/data_ingestion/data_pipeline.py +567 -0
  87. mcli/ml/data_ingestion/stream_processor.py +512 -0
  88. mcli/ml/database/migrations/env.py +94 -0
  89. mcli/ml/database/models.py +667 -0
  90. mcli/ml/database/session.py +200 -0
  91. mcli/ml/experimentation/ab_testing.py +845 -0
  92. mcli/ml/features/ensemble_features.py +607 -0
  93. mcli/ml/features/political_features.py +676 -0
  94. mcli/ml/features/recommendation_engine.py +809 -0
  95. mcli/ml/features/stock_features.py +573 -0
  96. mcli/ml/features/test_feature_engineering.py +346 -0
  97. mcli/ml/logging.py +85 -0
  98. mcli/ml/mlops/data_versioning.py +518 -0
  99. mcli/ml/mlops/experiment_tracker.py +377 -0
  100. mcli/ml/mlops/model_serving.py +481 -0
  101. mcli/ml/mlops/pipeline_orchestrator.py +614 -0
  102. mcli/ml/models/base_models.py +324 -0
  103. mcli/ml/models/ensemble_models.py +675 -0
  104. mcli/ml/models/recommendation_models.py +474 -0
  105. mcli/ml/models/test_models.py +487 -0
  106. mcli/ml/monitoring/drift_detection.py +676 -0
  107. mcli/ml/monitoring/metrics.py +45 -0
  108. mcli/ml/optimization/portfolio_optimizer.py +834 -0
  109. mcli/ml/preprocessing/data_cleaners.py +451 -0
  110. mcli/ml/preprocessing/feature_extractors.py +491 -0
  111. mcli/ml/preprocessing/ml_pipeline.py +382 -0
  112. mcli/ml/preprocessing/politician_trading_preprocessor.py +569 -0
  113. mcli/ml/preprocessing/test_preprocessing.py +294 -0
  114. mcli/ml/scripts/populate_sample_data.py +200 -0
  115. mcli/ml/tasks.py +400 -0
  116. mcli/ml/tests/test_integration.py +429 -0
  117. mcli/ml/tests/test_training_dashboard.py +387 -0
  118. mcli/public/oi/oi.py +15 -0
  119. mcli/public/public.py +4 -0
  120. mcli/self/self_cmd.py +1246 -0
  121. mcli/workflow/daemon/api_daemon.py +800 -0
  122. mcli/workflow/daemon/async_command_database.py +681 -0
  123. mcli/workflow/daemon/async_process_manager.py +591 -0
  124. mcli/workflow/daemon/client.py +530 -0
  125. mcli/workflow/daemon/commands.py +1196 -0
  126. mcli/workflow/daemon/daemon.py +905 -0
  127. mcli/workflow/daemon/daemon_api.py +59 -0
  128. mcli/workflow/daemon/enhanced_daemon.py +571 -0
  129. mcli/workflow/daemon/process_cli.py +244 -0
  130. mcli/workflow/daemon/process_manager.py +439 -0
  131. mcli/workflow/daemon/test_daemon.py +275 -0
  132. mcli/workflow/dashboard/dashboard_cmd.py +113 -0
  133. mcli/workflow/docker/docker.py +0 -0
  134. mcli/workflow/file/file.py +100 -0
  135. mcli/workflow/gcloud/config.toml +21 -0
  136. mcli/workflow/gcloud/gcloud.py +58 -0
  137. mcli/workflow/git_commit/ai_service.py +328 -0
  138. mcli/workflow/git_commit/commands.py +430 -0
  139. mcli/workflow/lsh_integration.py +355 -0
  140. mcli/workflow/model_service/client.py +594 -0
  141. mcli/workflow/model_service/download_and_run_efficient_models.py +288 -0
  142. mcli/workflow/model_service/lightweight_embedder.py +397 -0
  143. mcli/workflow/model_service/lightweight_model_server.py +714 -0
  144. mcli/workflow/model_service/lightweight_test.py +241 -0
  145. mcli/workflow/model_service/model_service.py +1955 -0
  146. mcli/workflow/model_service/ollama_efficient_runner.py +425 -0
  147. mcli/workflow/model_service/pdf_processor.py +386 -0
  148. mcli/workflow/model_service/test_efficient_runner.py +234 -0
  149. mcli/workflow/model_service/test_example.py +315 -0
  150. mcli/workflow/model_service/test_integration.py +131 -0
  151. mcli/workflow/model_service/test_new_features.py +149 -0
  152. mcli/workflow/openai/openai.py +99 -0
  153. mcli/workflow/politician_trading/commands.py +1790 -0
  154. mcli/workflow/politician_trading/config.py +134 -0
  155. mcli/workflow/politician_trading/connectivity.py +490 -0
  156. mcli/workflow/politician_trading/data_sources.py +395 -0
  157. mcli/workflow/politician_trading/database.py +410 -0
  158. mcli/workflow/politician_trading/demo.py +248 -0
  159. mcli/workflow/politician_trading/models.py +165 -0
  160. mcli/workflow/politician_trading/monitoring.py +413 -0
  161. mcli/workflow/politician_trading/scrapers.py +966 -0
  162. mcli/workflow/politician_trading/scrapers_california.py +412 -0
  163. mcli/workflow/politician_trading/scrapers_eu.py +377 -0
  164. mcli/workflow/politician_trading/scrapers_uk.py +350 -0
  165. mcli/workflow/politician_trading/scrapers_us_states.py +438 -0
  166. mcli/workflow/politician_trading/supabase_functions.py +354 -0
  167. mcli/workflow/politician_trading/workflow.py +852 -0
  168. mcli/workflow/registry/registry.py +180 -0
  169. mcli/workflow/repo/repo.py +223 -0
  170. mcli/workflow/scheduler/commands.py +493 -0
  171. mcli/workflow/scheduler/cron_parser.py +238 -0
  172. mcli/workflow/scheduler/job.py +182 -0
  173. mcli/workflow/scheduler/monitor.py +139 -0
  174. mcli/workflow/scheduler/persistence.py +324 -0
  175. mcli/workflow/scheduler/scheduler.py +679 -0
  176. mcli/workflow/sync/sync_cmd.py +437 -0
  177. mcli/workflow/sync/test_cmd.py +314 -0
  178. mcli/workflow/videos/videos.py +242 -0
  179. mcli/workflow/wakatime/wakatime.py +11 -0
  180. mcli/workflow/workflow.py +37 -0
  181. mcli_framework-7.0.0.dist-info/METADATA +479 -0
  182. mcli_framework-7.0.0.dist-info/RECORD +186 -0
  183. mcli_framework-7.0.0.dist-info/WHEEL +5 -0
  184. mcli_framework-7.0.0.dist-info/entry_points.txt +7 -0
  185. mcli_framework-7.0.0.dist-info/licenses/LICENSE +21 -0
  186. mcli_framework-7.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,502 @@
1
+ """
2
+ Bridge module for integrating Rust extensions with Python code
3
+ """
4
+
5
+ import importlib.util
6
+ import os
7
+ import sys
8
+ from typing import Any, Dict, List, Optional, Union
9
+
10
+ from mcli.lib.logger.logger import get_logger
11
+
12
+ logger = get_logger(__name__)
13
+
14
+ # Global flags for Rust extension availability
15
+ _RUST_AVAILABLE = None
16
+ _RUST_TFIDF = None
17
+ _RUST_FILE_WATCHER = None
18
+ _RUST_COMMAND_MATCHER = None
19
+ _RUST_PROCESS_MANAGER = None
20
+
21
+
22
+ def check_rust_extensions() -> Dict[str, bool]:
23
+ """Check which Rust extensions are available"""
24
+ global _RUST_AVAILABLE, _RUST_TFIDF, _RUST_FILE_WATCHER, _RUST_COMMAND_MATCHER, _RUST_PROCESS_MANAGER
25
+
26
+ if _RUST_AVAILABLE is not None:
27
+ return {
28
+ "available": _RUST_AVAILABLE,
29
+ "tfidf": _RUST_TFIDF,
30
+ "file_watcher": _RUST_FILE_WATCHER,
31
+ "command_matcher": _RUST_COMMAND_MATCHER,
32
+ "process_manager": _RUST_PROCESS_MANAGER,
33
+ }
34
+
35
+ try:
36
+ import mcli_rust
37
+
38
+ _RUST_AVAILABLE = True
39
+
40
+ # Check individual components
41
+ _RUST_TFIDF = hasattr(mcli_rust, "TfIdfVectorizer")
42
+ _RUST_FILE_WATCHER = hasattr(mcli_rust, "FileWatcher")
43
+ _RUST_COMMAND_MATCHER = hasattr(mcli_rust, "CommandMatcher")
44
+ _RUST_PROCESS_MANAGER = hasattr(mcli_rust, "ProcessManager")
45
+
46
+ logger.info("Rust extensions loaded successfully")
47
+
48
+ except ImportError as e:
49
+ _RUST_AVAILABLE = False
50
+ _RUST_TFIDF = False
51
+ _RUST_FILE_WATCHER = False
52
+ _RUST_COMMAND_MATCHER = False
53
+ _RUST_PROCESS_MANAGER = False
54
+
55
+ logger.warning(f"Rust extensions not available: {e}")
56
+
57
+ return {
58
+ "available": _RUST_AVAILABLE,
59
+ "tfidf": _RUST_TFIDF,
60
+ "file_watcher": _RUST_FILE_WATCHER,
61
+ "command_matcher": _RUST_COMMAND_MATCHER,
62
+ "process_manager": _RUST_PROCESS_MANAGER,
63
+ }
64
+
65
+
66
+ def get_tfidf_vectorizer(use_rust: bool = True, **kwargs):
67
+ """Get the best available TF-IDF vectorizer"""
68
+ rust_status = check_rust_extensions()
69
+
70
+ if use_rust and rust_status["tfidf"]:
71
+ try:
72
+ import mcli_rust
73
+
74
+ return mcli_rust.TfIdfVectorizer(**kwargs)
75
+ except Exception as e:
76
+ logger.warning(f"Failed to create Rust TF-IDF vectorizer: {e}")
77
+
78
+ # Fallback to sklearn
79
+ try:
80
+ from sklearn.feature_extraction.text import TfidfVectorizer
81
+
82
+ return TfidfVectorizer(**kwargs)
83
+ except ImportError:
84
+ raise RuntimeError("No TF-IDF vectorizer implementation available")
85
+
86
+
87
+ def get_file_watcher(use_rust: bool = True):
88
+ """Get the best available file watcher"""
89
+ rust_status = check_rust_extensions()
90
+
91
+ if use_rust and rust_status["file_watcher"]:
92
+ try:
93
+ import mcli_rust
94
+
95
+ return mcli_rust.FileWatcher()
96
+ except Exception as e:
97
+ logger.warning(f"Failed to create Rust file watcher: {e}")
98
+
99
+ # Fallback to Python watchdog
100
+ try:
101
+ from mcli.lib.watcher.python_watcher import PythonFileWatcher
102
+
103
+ return PythonFileWatcher()
104
+ except ImportError:
105
+ raise RuntimeError("No file watcher implementation available")
106
+
107
+
108
+ def get_command_matcher(use_rust: bool = True, **kwargs):
109
+ """Get the best available command matcher"""
110
+ rust_status = check_rust_extensions()
111
+
112
+ if use_rust and rust_status["command_matcher"]:
113
+ try:
114
+ import mcli_rust
115
+
116
+ return mcli_rust.CommandMatcher(**kwargs)
117
+ except Exception as e:
118
+ logger.warning(f"Failed to create Rust command matcher: {e}")
119
+
120
+ # Fallback to Python implementation
121
+ try:
122
+ from mcli.lib.discovery.python_matcher import PythonCommandMatcher
123
+
124
+ return PythonCommandMatcher(**kwargs)
125
+ except ImportError:
126
+ raise RuntimeError("No command matcher implementation available")
127
+
128
+
129
+ def get_process_manager(use_rust: bool = True):
130
+ """Get the best available process manager"""
131
+ rust_status = check_rust_extensions()
132
+
133
+ if use_rust and rust_status["process_manager"]:
134
+ try:
135
+ import mcli_rust
136
+
137
+ return mcli_rust.ProcessManager()
138
+ except Exception as e:
139
+ logger.warning(f"Failed to create Rust process manager: {e}")
140
+
141
+ # Fallback to async Python implementation
142
+ try:
143
+ from mcli.workflow.daemon.async_process_manager import AsyncProcessManager
144
+
145
+ return AsyncProcessManager()
146
+ except ImportError:
147
+ raise RuntimeError("No process manager implementation available")
148
+
149
+
150
+ class PerformanceMonitor:
151
+ """Monitor performance differences between Rust and Python implementations"""
152
+
153
+ def __init__(self):
154
+ self.benchmarks = {}
155
+ self.rust_status = check_rust_extensions()
156
+
157
+ def benchmark_tfidf(self, documents: List[str], queries: List[str]) -> Dict[str, Any]:
158
+ """Benchmark TF-IDF performance"""
159
+ import time
160
+
161
+ results = {"rust": None, "python": None, "speedup": None}
162
+
163
+ # Benchmark Rust implementation
164
+ if self.rust_status["tfidf"]:
165
+ try:
166
+ vectorizer = get_tfidf_vectorizer(use_rust=True)
167
+
168
+ start_time = time.perf_counter()
169
+ vectors = vectorizer.fit_transform(documents)
170
+ for query in queries:
171
+ similarities = vectorizer.similarity(query, documents)
172
+ rust_time = time.perf_counter() - start_time
173
+
174
+ results["rust"] = rust_time
175
+
176
+ except Exception as e:
177
+ logger.warning(f"Rust TF-IDF benchmark failed: {e}")
178
+
179
+ # Benchmark Python implementation
180
+ try:
181
+ vectorizer = get_tfidf_vectorizer(use_rust=False)
182
+
183
+ start_time = time.perf_counter()
184
+ vectors = vectorizer.fit_transform(documents)
185
+ for query in queries:
186
+ query_vec = vectorizer.transform([query])
187
+ # Compute similarities manually for fair comparison
188
+ similarities = []
189
+ for doc_vec in vectors:
190
+ sim = self._cosine_similarity(query_vec[0], doc_vec)
191
+ similarities.append(sim)
192
+ python_time = time.perf_counter() - start_time
193
+
194
+ results["python"] = python_time
195
+
196
+ except Exception as e:
197
+ logger.warning(f"Python TF-IDF benchmark failed: {e}")
198
+
199
+ # Calculate speedup
200
+ if results["rust"] and results["python"]:
201
+ results["speedup"] = results["python"] / results["rust"]
202
+
203
+ return results
204
+
205
+ def _cosine_similarity(self, vec1, vec2):
206
+ """Simple cosine similarity implementation"""
207
+ import numpy as np
208
+
209
+ dot_product = np.dot(
210
+ vec1.toarray()[0] if hasattr(vec1, "toarray") else vec1,
211
+ vec2.toarray()[0] if hasattr(vec2, "toarray") else vec2,
212
+ )
213
+ norm1 = np.linalg.norm(vec1.toarray()[0] if hasattr(vec1, "toarray") else vec1)
214
+ norm2 = np.linalg.norm(vec2.toarray()[0] if hasattr(vec2, "toarray") else vec2)
215
+
216
+ if norm1 == 0 or norm2 == 0:
217
+ return 0.0
218
+
219
+ return dot_product / (norm1 * norm2)
220
+
221
+ def benchmark_file_watching(self, test_dir: str, num_operations: int = 100) -> Dict[str, Any]:
222
+ """Benchmark file watching performance"""
223
+ import os
224
+ import tempfile
225
+ import time
226
+
227
+ results = {"rust": None, "python": None, "speedup": None}
228
+
229
+ # Create test directory
230
+ with tempfile.TemporaryDirectory() as temp_dir:
231
+ # Benchmark Rust implementation
232
+ if self.rust_status["file_watcher"]:
233
+ try:
234
+ watcher = get_file_watcher(use_rust=True)
235
+ watcher.start_watching([temp_dir])
236
+
237
+ start_time = time.perf_counter()
238
+ for i in range(num_operations):
239
+ test_file = os.path.join(temp_dir, f"test_{i}.txt")
240
+ with open(test_file, "w") as f:
241
+ f.write(f"test content {i}")
242
+ os.remove(test_file)
243
+
244
+ # Give time for events to be processed
245
+ time.sleep(0.1)
246
+ events = watcher.get_events()
247
+ rust_time = time.perf_counter() - start_time
248
+
249
+ watcher.stop_watching()
250
+ results["rust"] = rust_time
251
+
252
+ except Exception as e:
253
+ logger.warning(f"Rust file watcher benchmark failed: {e}")
254
+
255
+ # Benchmark Python implementation would require similar setup
256
+ # but is more complex due to different API
257
+
258
+ return results
259
+
260
+ def get_system_info(self) -> Dict[str, Any]:
261
+ """Get system information relevant to performance"""
262
+ import platform
263
+
264
+ import psutil
265
+
266
+ return {
267
+ "platform": platform.platform(),
268
+ "python_version": platform.python_version(),
269
+ "cpu_count": psutil.cpu_count(),
270
+ "memory_total": psutil.virtual_memory().total,
271
+ "rust_extensions": self.rust_status,
272
+ }
273
+
274
+
275
+ # Fallback implementations for when Rust extensions are not available
276
+
277
+
278
+ class PythonFileWatcher:
279
+ """Fallback Python file watcher using watchdog"""
280
+
281
+ def __init__(self):
282
+ from watchdog.events import FileSystemEventHandler
283
+ from watchdog.observers import Observer
284
+
285
+ class EventHandler(FileSystemEventHandler):
286
+ def __init__(self):
287
+ self.events = []
288
+
289
+ def on_any_event(self, event):
290
+ self.events.append(
291
+ {
292
+ "event_type": event.event_type,
293
+ "path": event.src_path,
294
+ "is_directory": event.is_directory,
295
+ }
296
+ )
297
+
298
+ self.observer = Observer()
299
+ self.handler = EventHandler()
300
+ self.is_watching = False
301
+
302
+ def start_watching(self, paths: List[str], recursive: bool = True):
303
+ from watchdog.observers import Observer
304
+
305
+ for path in paths:
306
+ self.observer.schedule(self.handler, path, recursive=recursive)
307
+
308
+ self.observer.start()
309
+ self.is_watching = True
310
+
311
+ def stop_watching(self):
312
+ if self.is_watching:
313
+ self.observer.stop()
314
+ self.observer.join()
315
+ self.is_watching = False
316
+
317
+ def get_events(self):
318
+ events = self.handler.events.copy()
319
+ self.handler.events.clear()
320
+ return events
321
+
322
+
323
+ class PythonCommandMatcher:
324
+ """Fallback Python command matcher"""
325
+
326
+ def __init__(self, fuzzy_threshold: float = 0.3):
327
+ self.fuzzy_threshold = fuzzy_threshold
328
+ self.commands = []
329
+
330
+ def add_commands(self, commands: List[Dict[str, Any]]):
331
+ self.commands.extend(commands)
332
+
333
+ def search(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
334
+ import re
335
+
336
+ results = []
337
+ query_lower = query.lower()
338
+
339
+ for cmd in self.commands:
340
+ score = 0.0
341
+ matched_fields = []
342
+
343
+ # Exact name match
344
+ if cmd["name"].lower() == query_lower:
345
+ score = 1.0
346
+ matched_fields.append("name")
347
+ # Prefix match
348
+ elif cmd["name"].lower().startswith(query_lower):
349
+ score = 0.9
350
+ matched_fields.append("name")
351
+ # Contains match
352
+ elif query_lower in cmd["name"].lower():
353
+ score = 0.7
354
+ matched_fields.append("name")
355
+ # Description match
356
+ elif query_lower in cmd.get("description", "").lower():
357
+ score = 0.5
358
+ matched_fields.append("description")
359
+
360
+ if score >= self.fuzzy_threshold:
361
+ results.append(
362
+ {
363
+ "command": cmd,
364
+ "score": score,
365
+ "match_type": "python_fallback",
366
+ "matched_fields": matched_fields,
367
+ }
368
+ )
369
+
370
+ results.sort(key=lambda x: x["score"], reverse=True)
371
+ return results[:limit]
372
+
373
+
374
+ # Auto-check Rust extensions on module import
375
+ _RUST_EXTENSIONS_STATUS = check_rust_extensions()
376
+
377
+
378
+ def print_performance_summary():
379
+ """Print a stunning visual summary of available performance optimizations"""
380
+ try:
381
+ from rich.columns import Columns
382
+ from rich.panel import Panel
383
+ from rich.rule import Rule
384
+ from rich.text import Text
385
+
386
+ from mcli.lib.ui.visual_effects import ColorfulOutput, MCLIBanner, VisualTable, console
387
+
388
+ status = check_rust_extensions()
389
+
390
+ console.print()
391
+ console.print(Rule("🚀 MCLI Performance Optimizations Summary", style="bright_green"))
392
+ console.print()
393
+
394
+ # Check all optimization status
395
+ optimization_data = {
396
+ "rust": {"success": status["available"], "extensions": status},
397
+ "uvloop": {"success": False},
398
+ "redis": {"success": False},
399
+ "aiosqlite": {"success": False},
400
+ "python": {
401
+ "success": True,
402
+ "reason": "GC tuning, bytecode optimization, recursion limit adjustment",
403
+ },
404
+ }
405
+
406
+ # Check UVLoop
407
+ try:
408
+ import uvloop
409
+
410
+ optimization_data["uvloop"]["success"] = True
411
+ optimization_data["uvloop"]["reason"] = "High-performance event loop active"
412
+ except ImportError:
413
+ optimization_data["uvloop"]["reason"] = "Package not installed"
414
+
415
+ # Check Redis
416
+ try:
417
+ import redis
418
+
419
+ # Try to ping Redis server
420
+ client = redis.Redis(host="localhost", port=6379, decode_responses=True)
421
+ client.ping()
422
+ client.close()
423
+ optimization_data["redis"]["success"] = True
424
+ optimization_data["redis"]["reason"] = "Cache server connected"
425
+ except ImportError:
426
+ optimization_data["redis"]["reason"] = "Package not installed"
427
+ except Exception:
428
+ optimization_data["redis"]["reason"] = "Server not available"
429
+
430
+ # Check AIOSQLite
431
+ try:
432
+ import aiosqlite
433
+
434
+ optimization_data["aiosqlite"]["success"] = True
435
+ optimization_data["aiosqlite"]["reason"] = "Async database operations enabled"
436
+ except ImportError:
437
+ optimization_data["aiosqlite"]["reason"] = "Package not installed"
438
+
439
+ # Show performance table
440
+ performance_table = VisualTable.create_performance_table(optimization_data)
441
+ console.print(performance_table)
442
+ console.print()
443
+
444
+ # Show Rust extensions details if available
445
+ if status["available"]:
446
+ rust_table = VisualTable.create_rust_extensions_table(status)
447
+ console.print(rust_table)
448
+ console.print()
449
+
450
+ # Show celebration
451
+ ColorfulOutput.success("All Rust extensions loaded - Maximum performance activated!")
452
+ else:
453
+ ColorfulOutput.warning("Rust extensions not available - Using Python fallbacks")
454
+ console.print()
455
+
456
+ console.print(Rule("System Ready", style="bright_blue"))
457
+ console.print()
458
+
459
+ except ImportError:
460
+ # Fallback to original simple output if visual effects not available
461
+ status = check_rust_extensions()
462
+
463
+ print("\n🚀 MCLI Performance Optimizations Summary:")
464
+ print("=" * 50)
465
+
466
+ if status["available"]:
467
+ print("✅ Rust extensions loaded successfully!")
468
+ print(f" • TF-IDF Vectorizer: {'✅' if status['tfidf'] else '❌'}")
469
+ print(f" • File Watcher: {'✅' if status['file_watcher'] else '❌'}")
470
+ print(f" • Command Matcher: {'✅' if status['command_matcher'] else '❌'}")
471
+ print(f" • Process Manager: {'✅' if status['process_manager'] else '❌'}")
472
+ else:
473
+ print("⚠️ Rust extensions not available - using Python fallbacks")
474
+
475
+ # Check other optimizations
476
+ try:
477
+ import uvloop
478
+
479
+ print("✅ UVLoop available for async performance")
480
+ except ImportError:
481
+ print("⚠️ UVLoop not available - using default asyncio")
482
+
483
+ try:
484
+ import redis
485
+
486
+ print("✅ Redis available for caching")
487
+ except ImportError:
488
+ print("⚠️ Redis not available - caching disabled")
489
+
490
+ try:
491
+ import aiosqlite
492
+
493
+ print("✅ AIOSQLite available for async database operations")
494
+ except ImportError:
495
+ print("⚠️ AIOSQLite not available - using sync SQLite")
496
+
497
+ print()
498
+
499
+
500
+ # Print summary when module is imported (can be enabled with env var)
501
+ if os.environ.get("MCLI_SHOW_PERFORMANCE_SUMMARY", "0").lower() not in ("0", "false", "no"):
502
+ print_performance_summary()
@@ -0,0 +1,154 @@
1
+ """
2
+ UVLoop configuration for enhanced asyncio performance
3
+ """
4
+
5
+ import asyncio
6
+ import os
7
+ import sys
8
+ from typing import Optional
9
+
10
+
11
+ def install_uvloop(force: bool = False) -> bool:
12
+ """
13
+ Install uvloop as the default event loop policy for better performance.
14
+
15
+ Args:
16
+ force: Force installation even on non-Unix systems
17
+
18
+ Returns:
19
+ True if uvloop was successfully installed, False otherwise
20
+ """
21
+ # Check if uvloop should be used
22
+ if not should_use_uvloop() and not force:
23
+ return False
24
+
25
+ try:
26
+ import uvloop
27
+
28
+ # Install uvloop as the default event loop policy
29
+ asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
30
+
31
+ # Verify installation
32
+ loop = asyncio.new_event_loop()
33
+ is_uvloop = "uvloop" in str(type(loop))
34
+ loop.close()
35
+
36
+ if is_uvloop:
37
+ # Only print if explicitly requested
38
+ if os.environ.get("MCLI_VERBOSE_UVLOOP", "0").lower() in ("1", "true", "yes"):
39
+ print("✓ UVLoop installed successfully for enhanced async performance")
40
+ return True
41
+ else:
42
+ if os.environ.get("MCLI_VERBOSE_UVLOOP", "0").lower() in ("1", "true", "yes"):
43
+ print("⚠ UVLoop installation failed - using default asyncio")
44
+ return False
45
+
46
+ except ImportError:
47
+ if os.environ.get("MCLI_VERBOSE_UVLOOP", "0").lower() in ("1", "true", "yes"):
48
+ print("⚠ UVLoop not available - install with: pip install uvloop")
49
+ return False
50
+ except Exception as e:
51
+ if os.environ.get("MCLI_VERBOSE_UVLOOP", "0").lower() in ("1", "true", "yes"):
52
+ print(f"⚠ UVLoop installation failed: {e}")
53
+ return False
54
+
55
+
56
+ def should_use_uvloop() -> bool:
57
+ """
58
+ Determine if uvloop should be used based on platform and environment.
59
+
60
+ Returns:
61
+ True if uvloop should be used, False otherwise
62
+ """
63
+ # Only use uvloop on Unix-like systems
64
+ if sys.platform not in ("linux", "darwin"):
65
+ return False
66
+
67
+ # Check environment variable override
68
+ disable_uvloop = os.environ.get("MCLI_DISABLE_UVLOOP", "").lower()
69
+ if disable_uvloop in ("1", "true", "yes"):
70
+ return False
71
+
72
+ # Check if we're in certain environments where uvloop might cause issues
73
+ if is_jupyter_environment():
74
+ return False
75
+
76
+ return True
77
+
78
+
79
+ def is_jupyter_environment() -> bool:
80
+ """Check if running in Jupyter/IPython environment."""
81
+ try:
82
+ import IPython
83
+
84
+ return IPython.get_ipython() is not None
85
+ except ImportError:
86
+ return False
87
+
88
+
89
+ def get_event_loop_info() -> dict:
90
+ """Get information about the current event loop."""
91
+ try:
92
+ loop = asyncio.get_running_loop()
93
+ loop_type = str(type(loop))
94
+
95
+ info = {
96
+ "type": loop_type,
97
+ "is_uvloop": "uvloop" in loop_type,
98
+ "is_running": True,
99
+ "debug": loop.get_debug(),
100
+ }
101
+
102
+ # Get additional uvloop-specific info if available
103
+ if hasattr(loop, "_csock"):
104
+ info["uvloop_version"] = getattr(loop, "_uvloop_version", "unknown")
105
+
106
+ return info
107
+
108
+ except RuntimeError:
109
+ return {"type": "No running loop", "is_uvloop": False, "is_running": False, "debug": False}
110
+
111
+
112
+ def configure_event_loop_for_performance():
113
+ """Configure the event loop for optimal performance."""
114
+ try:
115
+ loop = asyncio.get_running_loop()
116
+
117
+ # Disable debug mode in production
118
+ if not os.environ.get("MCLI_DEBUG"):
119
+ loop.set_debug(False)
120
+
121
+ # Set task factory for better performance monitoring if needed
122
+ if os.environ.get("MCLI_MONITOR_TASKS"):
123
+ loop.set_task_factory(create_monitored_task)
124
+
125
+ except RuntimeError:
126
+ # No running loop - configuration will apply to next loop
127
+ pass
128
+
129
+
130
+ def create_monitored_task(loop, coro):
131
+ """Custom task factory for monitoring task performance."""
132
+ import time
133
+
134
+ class MonitoredTask(asyncio.Task):
135
+ def __init__(self, coro, *, loop=None):
136
+ super().__init__(coro, loop=loop)
137
+ self._start_time = time.perf_counter()
138
+
139
+ def _step(self, exc=None):
140
+ start = time.perf_counter()
141
+ try:
142
+ result = super()._step(exc)
143
+ return result
144
+ finally:
145
+ duration = time.perf_counter() - start
146
+ if duration > 0.1: # Log slow operations
147
+ print(f"Slow task step: {self.get_name()} took {duration:.3f}s")
148
+
149
+ return MonitoredTask(coro, loop=loop)
150
+
151
+
152
+ # Auto-install uvloop when module is imported (can be disabled with env var)
153
+ if os.environ.get("MCLI_AUTO_UVLOOP", "1").lower() not in ("0", "false", "no"):
154
+ install_uvloop()
@@ -0,0 +1,50 @@
1
+ import os
2
+ import pickle
3
+ from pathlib import Path
4
+ from typing import Callable, Generic, Type, TypeVar
5
+
6
+ import click
7
+
8
+ T = TypeVar("T")
9
+
10
+
11
+ class ObjectCache(Generic[T]):
12
+ def __init__(self, class_type: Type[T], app_name: str, factory: Callable[[], T] = None):
13
+ self.class_type = class_type
14
+ self.app_name = app_name
15
+ self.factory = factory or class_type
16
+
17
+ def get_cache_path(self) -> Path:
18
+ cache_dir = Path(os.path.expanduser(f"~/.cache/{self.app_name}"))
19
+ cache_dir.mkdir(parents=True, exist_ok=True)
20
+ return cache_dir / f"{self.class_type.__name__.lower()}.pickle"
21
+
22
+ def get_or_create(self) -> T:
23
+ cache_path = self.get_cache_path()
24
+
25
+ if cache_path.exists():
26
+ try:
27
+ with open(cache_path, "rb") as f:
28
+ obj = pickle.load(f)
29
+ if isinstance(obj, self.class_type):
30
+ return obj
31
+ except (pickle.UnpicklingError, EOFError):
32
+ cache_path.unlink()
33
+
34
+ # Create new instance if no cache exists or loading failed
35
+ obj = self.factory()
36
+
37
+ # Save to cache
38
+ with open(cache_path, "wb") as f:
39
+ pickle.dump(obj, f)
40
+
41
+ return obj
42
+
43
+ def clear(self) -> None:
44
+ """Remove the cached object if it exists."""
45
+ cache_path = self.get_cache_path()
46
+ if cache_path.exists():
47
+ cache_path.unlink()
48
+
49
+
50
+ __all__ = ["ObjectCache"]