mcli-framework 7.12.1__py3-none-any.whl → 7.12.3__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 (216) hide show
  1. mcli/app/__init__.py +0 -2
  2. mcli/app/commands_cmd.py +19 -23
  3. mcli/app/completion_helpers.py +5 -5
  4. mcli/app/init_cmd.py +10 -10
  5. mcli/app/lock_cmd.py +82 -27
  6. mcli/app/main.py +2 -8
  7. mcli/app/model/model.py +5 -10
  8. mcli/app/store_cmd.py +8 -8
  9. mcli/app/video/__init__.py +0 -2
  10. mcli/app/video/video.py +1 -14
  11. mcli/chat/chat.py +90 -108
  12. mcli/chat/command_rag.py +0 -4
  13. mcli/chat/enhanced_chat.py +32 -41
  14. mcli/chat/system_controller.py +37 -37
  15. mcli/chat/system_integration.py +4 -5
  16. mcli/cli.py +2 -3
  17. mcli/lib/api/api.py +4 -9
  18. mcli/lib/api/daemon_client.py +19 -20
  19. mcli/lib/api/daemon_client_local.py +1 -3
  20. mcli/lib/api/daemon_decorator.py +6 -6
  21. mcli/lib/api/mcli_decorators.py +4 -8
  22. mcli/lib/auth/__init__.py +0 -1
  23. mcli/lib/auth/auth.py +4 -5
  24. mcli/lib/auth/mcli_manager.py +7 -12
  25. mcli/lib/auth/token_util.py +5 -5
  26. mcli/lib/config/__init__.py +29 -1
  27. mcli/lib/config/config.py +0 -1
  28. mcli/lib/custom_commands.py +1 -1
  29. mcli/lib/discovery/command_discovery.py +15 -15
  30. mcli/lib/erd/erd.py +7 -7
  31. mcli/lib/files/files.py +1 -1
  32. mcli/lib/fs/__init__.py +31 -1
  33. mcli/lib/fs/fs.py +12 -13
  34. mcli/lib/lib.py +0 -1
  35. mcli/lib/logger/logger.py +7 -10
  36. mcli/lib/performance/optimizer.py +25 -27
  37. mcli/lib/performance/rust_bridge.py +22 -27
  38. mcli/lib/performance/uvloop_config.py +0 -1
  39. mcli/lib/pickles/__init__.py +0 -1
  40. mcli/lib/pickles/pickles.py +0 -2
  41. mcli/lib/secrets/commands.py +0 -2
  42. mcli/lib/secrets/manager.py +0 -1
  43. mcli/lib/secrets/repl.py +2 -3
  44. mcli/lib/secrets/store.py +1 -2
  45. mcli/lib/services/data_pipeline.py +34 -34
  46. mcli/lib/services/lsh_client.py +38 -40
  47. mcli/lib/shell/shell.py +2 -2
  48. mcli/lib/toml/__init__.py +0 -1
  49. mcli/lib/ui/styling.py +0 -1
  50. mcli/lib/ui/visual_effects.py +33 -41
  51. mcli/lib/watcher/watcher.py +0 -1
  52. mcli/ml/__init__.py +1 -1
  53. mcli/ml/api/__init__.py +1 -1
  54. mcli/ml/api/app.py +8 -9
  55. mcli/ml/api/middleware.py +10 -10
  56. mcli/ml/api/routers/__init__.py +1 -1
  57. mcli/ml/api/routers/admin_router.py +3 -3
  58. mcli/ml/api/routers/auth_router.py +17 -18
  59. mcli/ml/api/routers/backtest_router.py +2 -2
  60. mcli/ml/api/routers/data_router.py +2 -2
  61. mcli/ml/api/routers/model_router.py +14 -15
  62. mcli/ml/api/routers/monitoring_router.py +2 -2
  63. mcli/ml/api/routers/portfolio_router.py +2 -2
  64. mcli/ml/api/routers/prediction_router.py +10 -9
  65. mcli/ml/api/routers/trade_router.py +2 -2
  66. mcli/ml/api/routers/websocket_router.py +6 -7
  67. mcli/ml/api/schemas.py +2 -2
  68. mcli/ml/auth/__init__.py +1 -1
  69. mcli/ml/auth/auth_manager.py +22 -23
  70. mcli/ml/auth/models.py +17 -17
  71. mcli/ml/auth/permissions.py +17 -17
  72. mcli/ml/backtesting/__init__.py +1 -1
  73. mcli/ml/backtesting/backtest_engine.py +31 -35
  74. mcli/ml/backtesting/performance_metrics.py +12 -14
  75. mcli/ml/backtesting/run.py +1 -2
  76. mcli/ml/cache.py +35 -36
  77. mcli/ml/cli/__init__.py +1 -1
  78. mcli/ml/cli/main.py +21 -24
  79. mcli/ml/config/__init__.py +1 -1
  80. mcli/ml/config/settings.py +28 -29
  81. mcli/ml/configs/__init__.py +1 -1
  82. mcli/ml/configs/dvc_config.py +14 -15
  83. mcli/ml/configs/mlflow_config.py +12 -13
  84. mcli/ml/configs/mlops_manager.py +19 -21
  85. mcli/ml/dashboard/__init__.py +4 -4
  86. mcli/ml/dashboard/app.py +20 -30
  87. mcli/ml/dashboard/app_supabase.py +16 -19
  88. mcli/ml/dashboard/app_training.py +11 -14
  89. mcli/ml/dashboard/cli.py +2 -2
  90. mcli/ml/dashboard/common.py +2 -3
  91. mcli/ml/dashboard/components/__init__.py +1 -1
  92. mcli/ml/dashboard/components/charts.py +13 -11
  93. mcli/ml/dashboard/components/metrics.py +7 -7
  94. mcli/ml/dashboard/components/tables.py +12 -9
  95. mcli/ml/dashboard/overview.py +2 -2
  96. mcli/ml/dashboard/pages/__init__.py +1 -1
  97. mcli/ml/dashboard/pages/cicd.py +15 -18
  98. mcli/ml/dashboard/pages/debug_dependencies.py +7 -7
  99. mcli/ml/dashboard/pages/monte_carlo_predictions.py +11 -18
  100. mcli/ml/dashboard/pages/predictions_enhanced.py +24 -32
  101. mcli/ml/dashboard/pages/scrapers_and_logs.py +22 -24
  102. mcli/ml/dashboard/pages/test_portfolio.py +3 -6
  103. mcli/ml/dashboard/pages/trading.py +16 -18
  104. mcli/ml/dashboard/pages/workflows.py +20 -30
  105. mcli/ml/dashboard/utils.py +9 -9
  106. mcli/ml/dashboard/warning_suppression.py +3 -3
  107. mcli/ml/data_ingestion/__init__.py +1 -1
  108. mcli/ml/data_ingestion/api_connectors.py +41 -46
  109. mcli/ml/data_ingestion/data_pipeline.py +36 -46
  110. mcli/ml/data_ingestion/stream_processor.py +43 -46
  111. mcli/ml/database/__init__.py +1 -1
  112. mcli/ml/database/migrations/env.py +2 -2
  113. mcli/ml/database/models.py +22 -24
  114. mcli/ml/database/session.py +14 -14
  115. mcli/ml/experimentation/__init__.py +1 -1
  116. mcli/ml/experimentation/ab_testing.py +45 -46
  117. mcli/ml/features/__init__.py +1 -1
  118. mcli/ml/features/ensemble_features.py +22 -27
  119. mcli/ml/features/recommendation_engine.py +30 -30
  120. mcli/ml/features/stock_features.py +29 -32
  121. mcli/ml/features/test_feature_engineering.py +10 -11
  122. mcli/ml/logging.py +4 -4
  123. mcli/ml/mlops/__init__.py +1 -1
  124. mcli/ml/mlops/data_versioning.py +29 -30
  125. mcli/ml/mlops/experiment_tracker.py +24 -24
  126. mcli/ml/mlops/model_serving.py +31 -34
  127. mcli/ml/mlops/pipeline_orchestrator.py +27 -35
  128. mcli/ml/models/__init__.py +5 -6
  129. mcli/ml/models/base_models.py +23 -23
  130. mcli/ml/models/ensemble_models.py +31 -31
  131. mcli/ml/models/recommendation_models.py +18 -19
  132. mcli/ml/models/test_models.py +14 -16
  133. mcli/ml/monitoring/__init__.py +1 -1
  134. mcli/ml/monitoring/drift_detection.py +32 -36
  135. mcli/ml/monitoring/metrics.py +2 -2
  136. mcli/ml/optimization/__init__.py +1 -1
  137. mcli/ml/optimization/optimize.py +1 -2
  138. mcli/ml/optimization/portfolio_optimizer.py +30 -32
  139. mcli/ml/predictions/__init__.py +1 -1
  140. mcli/ml/preprocessing/__init__.py +1 -1
  141. mcli/ml/preprocessing/data_cleaners.py +22 -23
  142. mcli/ml/preprocessing/feature_extractors.py +23 -26
  143. mcli/ml/preprocessing/ml_pipeline.py +23 -23
  144. mcli/ml/preprocessing/test_preprocessing.py +7 -8
  145. mcli/ml/scripts/populate_sample_data.py +0 -4
  146. mcli/ml/serving/serve.py +1 -2
  147. mcli/ml/tasks.py +17 -17
  148. mcli/ml/tests/test_integration.py +29 -30
  149. mcli/ml/tests/test_training_dashboard.py +21 -21
  150. mcli/ml/trading/__init__.py +1 -1
  151. mcli/ml/trading/migrations.py +5 -5
  152. mcli/ml/trading/models.py +21 -23
  153. mcli/ml/trading/paper_trading.py +16 -13
  154. mcli/ml/trading/risk_management.py +17 -18
  155. mcli/ml/trading/trading_service.py +25 -28
  156. mcli/ml/training/__init__.py +1 -1
  157. mcli/ml/training/train.py +0 -1
  158. mcli/public/oi/oi.py +1 -2
  159. mcli/self/completion_cmd.py +6 -10
  160. mcli/self/logs_cmd.py +19 -24
  161. mcli/self/migrate_cmd.py +22 -20
  162. mcli/self/redis_cmd.py +10 -11
  163. mcli/self/self_cmd.py +10 -18
  164. mcli/self/store_cmd.py +10 -12
  165. mcli/self/visual_cmd.py +9 -14
  166. mcli/self/zsh_cmd.py +2 -4
  167. mcli/workflow/daemon/async_command_database.py +23 -24
  168. mcli/workflow/daemon/async_process_manager.py +27 -29
  169. mcli/workflow/daemon/client.py +27 -33
  170. mcli/workflow/daemon/daemon.py +32 -36
  171. mcli/workflow/daemon/enhanced_daemon.py +24 -33
  172. mcli/workflow/daemon/process_cli.py +11 -12
  173. mcli/workflow/daemon/process_manager.py +23 -26
  174. mcli/workflow/daemon/test_daemon.py +4 -5
  175. mcli/workflow/dashboard/dashboard_cmd.py +0 -1
  176. mcli/workflow/doc_convert.py +15 -17
  177. mcli/workflow/gcloud/__init__.py +0 -1
  178. mcli/workflow/gcloud/gcloud.py +11 -8
  179. mcli/workflow/git_commit/ai_service.py +14 -15
  180. mcli/workflow/lsh_integration.py +9 -11
  181. mcli/workflow/model_service/client.py +26 -31
  182. mcli/workflow/model_service/download_and_run_efficient_models.py +10 -14
  183. mcli/workflow/model_service/lightweight_embedder.py +25 -35
  184. mcli/workflow/model_service/lightweight_model_server.py +26 -32
  185. mcli/workflow/model_service/lightweight_test.py +7 -10
  186. mcli/workflow/model_service/model_service.py +80 -91
  187. mcli/workflow/model_service/ollama_efficient_runner.py +14 -18
  188. mcli/workflow/model_service/openai_adapter.py +23 -23
  189. mcli/workflow/model_service/pdf_processor.py +21 -26
  190. mcli/workflow/model_service/test_efficient_runner.py +12 -16
  191. mcli/workflow/model_service/test_example.py +11 -13
  192. mcli/workflow/model_service/test_integration.py +3 -5
  193. mcli/workflow/model_service/test_new_features.py +7 -8
  194. mcli/workflow/notebook/converter.py +1 -1
  195. mcli/workflow/notebook/notebook_cmd.py +5 -6
  196. mcli/workflow/notebook/schema.py +0 -1
  197. mcli/workflow/notebook/validator.py +7 -3
  198. mcli/workflow/openai/openai.py +1 -2
  199. mcli/workflow/registry/registry.py +4 -1
  200. mcli/workflow/repo/repo.py +6 -7
  201. mcli/workflow/scheduler/cron_parser.py +16 -19
  202. mcli/workflow/scheduler/job.py +10 -10
  203. mcli/workflow/scheduler/monitor.py +15 -15
  204. mcli/workflow/scheduler/persistence.py +17 -18
  205. mcli/workflow/scheduler/scheduler.py +37 -38
  206. mcli/workflow/secrets/__init__.py +1 -1
  207. mcli/workflow/sync/test_cmd.py +0 -1
  208. mcli/workflow/wakatime/__init__.py +5 -9
  209. mcli/workflow/wakatime/wakatime.py +1 -2
  210. {mcli_framework-7.12.1.dist-info → mcli_framework-7.12.3.dist-info}/METADATA +1 -1
  211. mcli_framework-7.12.3.dist-info/RECORD +279 -0
  212. mcli_framework-7.12.1.dist-info/RECORD +0 -279
  213. {mcli_framework-7.12.1.dist-info → mcli_framework-7.12.3.dist-info}/WHEEL +0 -0
  214. {mcli_framework-7.12.1.dist-info → mcli_framework-7.12.3.dist-info}/entry_points.txt +0 -0
  215. {mcli_framework-7.12.1.dist-info → mcli_framework-7.12.3.dist-info}/licenses/LICENSE +0 -0
  216. {mcli_framework-7.12.1.dist-info → mcli_framework-7.12.3.dist-info}/top_level.txt +0 -0
@@ -1,27 +1,24 @@
1
- """Trading service for managing portfolios and executing trades"""
1
+ """Trading service for managing portfolios and executing trades."""
2
2
 
3
3
  import logging
4
4
  from datetime import datetime, timedelta
5
5
  from decimal import Decimal
6
- from typing import Dict, List, Optional, Tuple, Union
6
+ from typing import Dict, List, Optional
7
7
  from uuid import UUID
8
8
 
9
9
  import pandas as pd
10
- from sqlalchemy import and_, desc, func
10
+ from sqlalchemy import desc
11
11
  from sqlalchemy.orm import Session
12
12
 
13
13
  from mcli.ml.trading.alpaca_client import AlpacaTradingClient, create_trading_client
14
14
  from mcli.ml.trading.models import (
15
15
  OrderCreate,
16
16
  OrderResponse,
17
- OrderSide,
18
17
  OrderStatus,
19
18
  OrderType,
20
19
  Portfolio,
21
20
  PortfolioCreate,
22
21
  PortfolioPerformanceSnapshot,
23
- PortfolioResponse,
24
- PortfolioType,
25
22
  Position,
26
23
  PositionResponse,
27
24
  PositionSide,
@@ -36,7 +33,7 @@ logger = logging.getLogger(__name__)
36
33
 
37
34
 
38
35
  class TradingService:
39
- """Service for managing trading operations"""
36
+ """Service for managing trading operations."""
40
37
 
41
38
  def __init__(self, db_session: Session):
42
39
  self.db = db_session
@@ -44,7 +41,7 @@ class TradingService:
44
41
  def create_trading_account(
45
42
  self, user_id: UUID, account_data: TradingAccountCreate
46
43
  ) -> TradingAccount:
47
- """Create a new trading account"""
44
+ """Create a new trading account."""
48
45
  try:
49
46
  account = TradingAccount(
50
47
  user_id=user_id,
@@ -71,15 +68,15 @@ class TradingService:
71
68
  raise
72
69
 
73
70
  def get_trading_account(self, account_id: UUID) -> Optional[TradingAccount]:
74
- """Get trading account by ID"""
71
+ """Get trading account by ID."""
75
72
  return (
76
73
  self.db.query(TradingAccount)
77
- .filter(TradingAccount.id == account_id, TradingAccount.is_active == True)
74
+ .filter(TradingAccount.id == account_id, TradingAccount.is_active is True)
78
75
  .first()
79
76
  )
80
77
 
81
78
  def create_portfolio(self, account_id: UUID, portfolio_data: PortfolioCreate) -> Portfolio:
82
- """Create a new portfolio"""
79
+ """Create a new portfolio."""
83
80
  try:
84
81
  portfolio = Portfolio(
85
82
  trading_account_id=account_id,
@@ -103,24 +100,24 @@ class TradingService:
103
100
  raise
104
101
 
105
102
  def get_portfolio(self, portfolio_id: UUID) -> Optional[Portfolio]:
106
- """Get portfolio by ID"""
103
+ """Get portfolio by ID."""
107
104
  return (
108
105
  self.db.query(Portfolio)
109
- .filter(Portfolio.id == portfolio_id, Portfolio.is_active == True)
106
+ .filter(Portfolio.id == portfolio_id, Portfolio.is_active is True)
110
107
  .first()
111
108
  )
112
109
 
113
110
  def get_user_portfolios(self, user_id: UUID) -> List[Portfolio]:
114
- """Get all portfolios for a user"""
111
+ """Get all portfolios for a user."""
115
112
  return (
116
113
  self.db.query(Portfolio)
117
114
  .join(TradingAccount)
118
- .filter(TradingAccount.user_id == user_id, Portfolio.is_active == True)
115
+ .filter(TradingAccount.user_id == user_id, Portfolio.is_active is True)
119
116
  .all()
120
117
  )
121
118
 
122
119
  def create_alpaca_client(self, account: TradingAccount) -> AlpacaTradingClient:
123
- """Create Alpaca client for trading account"""
120
+ """Create Alpaca client for trading account."""
124
121
  if not account.alpaca_api_key or not account.alpaca_secret_key:
125
122
  raise ValueError("Alpaca credentials not configured for this account")
126
123
 
@@ -131,7 +128,7 @@ class TradingService:
131
128
  )
132
129
 
133
130
  def sync_portfolio_with_alpaca(self, portfolio: Portfolio) -> bool:
134
- """Sync portfolio data with Alpaca"""
131
+ """Sync portfolio data with Alpaca."""
135
132
  try:
136
133
  account = self.get_trading_account(portfolio.trading_account_id)
137
134
  if not account:
@@ -168,7 +165,7 @@ class TradingService:
168
165
  return False
169
166
 
170
167
  def _sync_positions(self, portfolio: Portfolio, alpaca_positions: List):
171
- """Sync positions with Alpaca data"""
168
+ """Sync positions with Alpaca data."""
172
169
  # Clear existing positions
173
170
  self.db.query(Position).filter(Position.portfolio_id == portfolio.id).delete()
174
171
 
@@ -191,7 +188,7 @@ class TradingService:
191
188
  self.db.add(position)
192
189
 
193
190
  def _create_performance_snapshot(self, portfolio: Portfolio):
194
- """Create daily performance snapshot"""
191
+ """Create daily performance snapshot."""
195
192
  snapshot = PortfolioPerformanceSnapshot(
196
193
  portfolio_id=portfolio.id,
197
194
  snapshot_date=datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0),
@@ -209,7 +206,7 @@ class TradingService:
209
206
  self.db.add(snapshot)
210
207
 
211
208
  def _get_positions_data(self, portfolio_id: UUID) -> Dict:
212
- """Get positions data for snapshot"""
209
+ """Get positions data for snapshot."""
213
210
  positions = self.db.query(Position).filter(Position.portfolio_id == portfolio_id).all()
214
211
  return {
215
212
  pos.symbol: {
@@ -227,7 +224,7 @@ class TradingService:
227
224
  def place_order(
228
225
  self, portfolio_id: UUID, order_data: OrderCreate, check_risk: bool = True
229
226
  ) -> TradingOrder:
230
- """Place a trading order"""
227
+ """Place a trading order."""
231
228
  try:
232
229
  portfolio = self.get_portfolio(portfolio_id)
233
230
  if not portfolio:
@@ -311,7 +308,7 @@ class TradingService:
311
308
  raise
312
309
 
313
310
  def get_portfolio_positions(self, portfolio_id: UUID) -> List[PositionResponse]:
314
- """Get all positions for a portfolio"""
311
+ """Get all positions for a portfolio."""
315
312
  positions = self.db.query(Position).filter(Position.portfolio_id == portfolio_id).all()
316
313
  return [
317
314
  PositionResponse(
@@ -337,7 +334,7 @@ class TradingService:
337
334
  def get_portfolio_orders(
338
335
  self, portfolio_id: UUID, status: Optional[OrderStatus] = None
339
336
  ) -> List[OrderResponse]:
340
- """Get orders for a portfolio"""
337
+ """Get orders for a portfolio."""
341
338
  query = self.db.query(TradingOrder).filter(TradingOrder.portfolio_id == portfolio_id)
342
339
  if status:
343
340
  query = query.filter(TradingOrder.status == status)
@@ -370,7 +367,7 @@ class TradingService:
370
367
  ]
371
368
 
372
369
  def get_portfolio_performance(self, portfolio_id: UUID, days: int = 30) -> pd.DataFrame:
373
- """Get portfolio performance history"""
370
+ """Get portfolio performance history."""
374
371
  end_date = datetime.utcnow()
375
372
  start_date = end_date - timedelta(days=days)
376
373
 
@@ -417,7 +414,7 @@ class TradingService:
417
414
  position_size: Optional[float] = None,
418
415
  expires_hours: int = 24,
419
416
  ) -> TradingSignal:
420
- """Create a trading signal"""
417
+ """Create a trading signal."""
421
418
  try:
422
419
  expires_at = (
423
420
  datetime.utcnow() + timedelta(hours=expires_hours) if expires_hours > 0 else None
@@ -450,12 +447,12 @@ class TradingService:
450
447
  raise
451
448
 
452
449
  def get_active_signals(self, portfolio_id: UUID) -> List[TradingSignalResponse]:
453
- """Get active trading signals for a portfolio"""
450
+ """Get active trading signals for a portfolio."""
454
451
  signals = (
455
452
  self.db.query(TradingSignal)
456
453
  .filter(
457
454
  TradingSignal.portfolio_id == portfolio_id,
458
- TradingSignal.is_active == True,
455
+ TradingSignal.is_active is True,
459
456
  TradingSignal.expires_at > datetime.utcnow(),
460
457
  )
461
458
  .order_by(desc(TradingSignal.created_at))
@@ -483,7 +480,7 @@ class TradingService:
483
480
  ]
484
481
 
485
482
  def calculate_portfolio_metrics(self, portfolio_id: UUID) -> Dict:
486
- """Calculate portfolio performance metrics"""
483
+ """Calculate portfolio performance metrics."""
487
484
  portfolio = self.get_portfolio(portfolio_id)
488
485
  if not portfolio:
489
486
  return {}
@@ -1,4 +1,4 @@
1
- """ML model training module"""
1
+ """ML model training module."""
2
2
 
3
3
  from .train_model import PoliticianTradingNet, fetch_training_data
4
4
  from .train_model import main as train_model
mcli/ml/training/train.py CHANGED
@@ -9,7 +9,6 @@ from mcli.lib.ui.styling import error, info, success
9
9
  @click.group(name="mcli-train", help="Model training CLI for MCLI ML system")
10
10
  def cli():
11
11
  """Main CLI group for model training."""
12
- pass
13
12
 
14
13
 
15
14
  @cli.command(name="model", help="Train a model")
mcli/public/oi/oi.py CHANGED
@@ -5,10 +5,9 @@ from mcli.lib.shell.shell import get_shell_script_path, shell_exec
5
5
 
6
6
  @click.group(name="oi")
7
7
  def oi():
8
- """Create an alpha tunnel using the instance"""
8
+ """Create an alpha tunnel using the instance."""
9
9
  scripts_path = get_shell_script_path("oi", __name__)
10
10
  shell_exec(scripts_path, "oi")
11
- pass
12
11
 
13
12
 
14
13
  if __name__ == "__main__":
@@ -10,19 +10,16 @@ from pathlib import Path
10
10
 
11
11
  import click
12
12
 
13
- from mcli.lib.ui.styling import success
14
-
15
13
 
16
14
  @click.group(name="completion")
17
15
  def completion():
18
- """Shell completion utilities"""
19
- pass
16
+ """Shell completion utilities."""
20
17
 
21
18
 
22
19
  @completion.command(name="bash")
23
20
  @click.pass_context
24
21
  def bash_completion(ctx):
25
- """Generate bash completion script"""
22
+ """Generate bash completion script."""
26
23
  from click.shell_completion import BashComplete
27
24
 
28
25
  # Get the root CLI app
@@ -39,7 +36,7 @@ def bash_completion(ctx):
39
36
  @completion.command(name="zsh")
40
37
  @click.pass_context
41
38
  def zsh_completion(ctx):
42
- """Generate zsh completion script"""
39
+ """Generate zsh completion script."""
43
40
  from click.shell_completion import ZshComplete
44
41
 
45
42
  # Get the root CLI app
@@ -56,7 +53,7 @@ def zsh_completion(ctx):
56
53
  @completion.command(name="fish")
57
54
  @click.pass_context
58
55
  def fish_completion(ctx):
59
- """Generate fish completion script"""
56
+ """Generate fish completion script."""
60
57
  from click.shell_completion import FishComplete
61
58
 
62
59
  # Get the root CLI app
@@ -78,8 +75,7 @@ def fish_completion(ctx):
78
75
  )
79
76
  @click.pass_context
80
77
  def install_completion(ctx, shell):
81
- """Install shell completion for the current user"""
82
- import subprocess
78
+ """Install shell completion for the current user."""
83
79
 
84
80
  # Auto-detect shell if not specified
85
81
  if not shell:
@@ -180,7 +176,7 @@ def install_completion(ctx, shell):
180
176
 
181
177
  @completion.command(name="status")
182
178
  def completion_status():
183
- """Check current shell completion status"""
179
+ """Check current shell completion status."""
184
180
  current_shell = os.environ.get("SHELL", "unknown")
185
181
  shell_name = Path(current_shell).name if current_shell != "unknown" else "unknown"
186
182
 
mcli/self/logs_cmd.py CHANGED
@@ -2,9 +2,7 @@
2
2
  Log streaming and management commands
3
3
  """
4
4
 
5
- import os
6
5
  import subprocess
7
- import sys
8
6
  import time
9
7
  from datetime import datetime
10
8
  from pathlib import Path
@@ -12,8 +10,6 @@ from typing import Optional
12
10
 
13
11
  import click
14
12
  from rich.console import Console
15
- from rich.live import Live
16
- from rich.panel import Panel
17
13
  from rich.text import Text
18
14
 
19
15
  from mcli.lib.paths import get_logs_dir
@@ -23,16 +19,15 @@ console = Console()
23
19
 
24
20
  @click.group(name="logs")
25
21
  def logs_group():
26
- """Stream and manage MCLI log files"""
27
- pass
22
+ """Stream and manage MCLI log files."""
28
23
 
29
24
 
30
25
  @logs_group.command(name="location")
31
26
  def show_location():
32
- """Show the location of the logs directory"""
27
+ """Show the location of the logs directory."""
33
28
  logs_dir = get_logs_dir()
34
29
  console.print(f"📁 [cyan]Logs directory:[/cyan] {logs_dir}")
35
- console.print(f" [dim]Set MCLI_HOME environment variable to change location[/dim]")
30
+ console.print(" [dim]Set MCLI_HOME environment variable to change location[/dim]")
36
31
 
37
32
  # Show if directory exists and has files
38
33
  if logs_dir.exists():
@@ -40,9 +35,9 @@ def show_location():
40
35
  if log_files:
41
36
  console.print(f" [green]✓ {len(log_files)} log file(s) found[/green]")
42
37
  else:
43
- console.print(f" [yellow]⚠ Directory exists but no log files yet[/yellow]")
38
+ console.print(" [yellow]⚠ Directory exists but no log files yet[/yellow]")
44
39
  else:
45
- console.print(f" [yellow]⚠ Directory will be created on first use[/yellow]")
40
+ console.print(" [yellow]⚠ Directory will be created on first use[/yellow]")
46
41
 
47
42
 
48
43
  @logs_group.command(name="stream")
@@ -111,7 +106,7 @@ def stream_logs(type: str, lines: int, follow: bool):
111
106
  @logs_group.command(name="list")
112
107
  @click.option("--date", "-d", help="Show logs for specific date (YYYYMMDD format)")
113
108
  def list_logs(date: Optional[str]):
114
- """List available log files"""
109
+ """List available log files."""
115
110
  logs_dir = get_logs_dir()
116
111
  _list_available_logs(logs_dir, date)
117
112
 
@@ -207,7 +202,7 @@ def tail_logs(log_type: str, lines: int, date: Optional[str], follow: bool):
207
202
  "--context", "-C", type=int, default=3, help="Lines of context around matches (default: 3)"
208
203
  )
209
204
  def grep_logs(pattern: str, type: str, date: Optional[str], context: int):
210
- """Search for patterns in log files"""
205
+ """Search for patterns in log files."""
211
206
  logs_dir = get_logs_dir()
212
207
 
213
208
  # Use provided date or default to today
@@ -251,7 +246,7 @@ def grep_logs(pattern: str, type: str, date: Optional[str], context: int):
251
246
  @click.option("--older-than", type=int, help="Clear logs older than N days")
252
247
  @click.option("--confirm", "-y", is_flag=True, help="Skip confirmation prompt")
253
248
  def clear_logs(older_than: Optional[int], confirm: bool):
254
- """Clear old log files"""
249
+ """Clear old log files."""
255
250
  logs_dir = get_logs_dir()
256
251
 
257
252
  # Find log files
@@ -273,7 +268,7 @@ def clear_logs(older_than: Optional[int], confirm: bool):
273
268
  return
274
269
 
275
270
  # Show what will be deleted
276
- console.print(f"📋 **Log files to clear:**", style="yellow")
271
+ console.print("📋 **Log files to clear:**", style="yellow")
277
272
  total_size = 0
278
273
  for log_file in log_files:
279
274
  size = log_file.stat().st_size
@@ -283,7 +278,7 @@ def clear_logs(older_than: Optional[int], confirm: bool):
283
278
  console.print(f"\n📊 **Total size:** {_format_file_size(total_size)}", style="cyan")
284
279
 
285
280
  # Confirm deletion
286
- if not confirm:
281
+ if not confirm: # noqa: SIM102
287
282
  if not click.confirm(f"\nDelete {len(log_files)} log files?"):
288
283
  console.print("❌ Operation cancelled", style="yellow")
289
284
  return
@@ -304,7 +299,7 @@ def clear_logs(older_than: Optional[int], confirm: bool):
304
299
 
305
300
 
306
301
  def _stream_single_file(log_file: Path, lines: int, follow: bool):
307
- """Stream a single log file"""
302
+ """Stream a single log file."""
308
303
  console.print(f"📡 **Streaming {log_file.name}**", style="cyan")
309
304
  console.print("Press Ctrl+C to stop\n")
310
305
 
@@ -332,7 +327,7 @@ def _stream_single_file(log_file: Path, lines: int, follow: bool):
332
327
 
333
328
 
334
329
  def _stream_multiple_files(log_files: list, lines: int, follow: bool):
335
- """Stream multiple log files simultaneously"""
330
+ """Stream multiple log files simultaneously."""
336
331
  console.print(f"📡 **Streaming {len(log_files)} log files**", style="cyan")
337
332
  for log_file in log_files:
338
333
  console.print(f" • {log_file.name}")
@@ -340,7 +335,7 @@ def _stream_multiple_files(log_files: list, lines: int, follow: bool):
340
335
 
341
336
  # Use multitail or custom implementation
342
337
  # For simplicity, we'll cycle through files
343
- try:
338
+ try: # noqa: SIM105
344
339
  while True:
345
340
  for log_file in log_files:
346
341
  if log_file.exists():
@@ -365,7 +360,7 @@ def _stream_multiple_files(log_files: list, lines: int, follow: bool):
365
360
 
366
361
 
367
362
  def _format_log_line(line: str) -> Text:
368
- """Format a log line with syntax highlighting"""
363
+ """Format a log line with syntax highlighting."""
369
364
  text = Text()
370
365
 
371
366
  # Color-code by log level
@@ -384,7 +379,7 @@ def _format_log_line(line: str) -> Text:
384
379
 
385
380
 
386
381
  def _list_available_logs(logs_dir: Path, date_filter: Optional[str] = None):
387
- """List available log files"""
382
+ """List available log files."""
388
383
  log_files = sorted(logs_dir.glob("mcli*.log"))
389
384
 
390
385
  if not log_files:
@@ -409,7 +404,7 @@ def _list_available_logs(logs_dir: Path, date_filter: Optional[str] = None):
409
404
 
410
405
 
411
406
  def _search_log_file(log_file: Path, pattern: str, context: int) -> list:
412
- """Search for pattern in log file with context"""
407
+ """Search for pattern in log file with context."""
413
408
  matches = []
414
409
 
415
410
  try:
@@ -425,7 +420,7 @@ def _search_log_file(log_file: Path, pattern: str, context: int) -> list:
425
420
  context_lines = []
426
421
  for j in range(start, end):
427
422
  prefix = ">>> " if j == i else " "
428
- style = "bright_yellow" if j == i else "dim"
423
+ _style = "bright_yellow" if j == i else "dim" # noqa: F841
429
424
  context_lines.append(f"{prefix}{lines[j].rstrip()}")
430
425
 
431
426
  matches.append("\n".join(context_lines) + "\n")
@@ -437,7 +432,7 @@ def _search_log_file(log_file: Path, pattern: str, context: int) -> list:
437
432
 
438
433
 
439
434
  def _format_file_size(size_bytes: int) -> str:
440
- """Format file size in human readable format"""
435
+ """Format file size in human readable format."""
441
436
  for unit in ["B", "KB", "MB", "GB"]:
442
437
  if size_bytes < 1024.0:
443
438
  return f"{size_bytes:.1f} {unit}"
@@ -447,5 +442,5 @@ def _format_file_size(size_bytes: int) -> str:
447
442
 
448
443
  # Register with main CLI
449
444
  def register_logs_commands(cli):
450
- """Register logs commands with the main CLI"""
445
+ """Register logs commands with the main CLI."""
451
446
  cli.add_command(logs_group)
mcli/self/migrate_cmd.py CHANGED
@@ -7,7 +7,6 @@ Handles migrations between different versions of mcli, including:
7
7
  - Command structure changes
8
8
  """
9
9
 
10
- import json
11
10
  import shutil
12
11
  from datetime import datetime
13
12
  from pathlib import Path
@@ -15,11 +14,10 @@ from typing import List, Tuple
15
14
 
16
15
  import click
17
16
  from rich.console import Console
18
- from rich.panel import Panel
19
17
  from rich.table import Table
20
18
 
21
19
  from mcli.lib.logger.logger import get_logger
22
- from mcli.lib.ui.styling import error, info, success, warning
20
+ from mcli.lib.ui.styling import error, info, success
23
21
 
24
22
  logger = get_logger(__name__)
25
23
  console = Console()
@@ -82,9 +80,7 @@ def get_migration_status() -> dict:
82
80
  }
83
81
 
84
82
  if local_old.exists():
85
- files = [
86
- f for f in local_old.iterdir() if f.is_file() and not f.name.startswith(".")
87
- ]
83
+ files = [f for f in local_old.iterdir() if f.is_file() and not f.name.startswith(".")]
88
84
  status["local"]["files_to_migrate"] = [f.name for f in files]
89
85
  status["local"]["needs_migration"] = len(files) > 0
90
86
 
@@ -289,19 +285,19 @@ def migrate_command(dry_run: bool, force: bool, status: bool, scope: str):
289
285
 
290
286
  # Show global status
291
287
  global_status = migration_status["global"]
292
- console.print(f"\n[bold]Global (~/.mcli)[/bold]")
288
+ console.print("\n[bold]Global (~/.mcli)[/bold]")
293
289
  console.print(f" Old location: {global_status['old_dir_path']}")
294
290
  console.print(f" Exists: {'✓ Yes' if global_status['old_dir_exists'] else '✗ No'}")
295
291
  console.print(f" New location: {global_status['new_dir_path']}")
296
292
  console.print(f" Exists: {'✓ Yes' if global_status['new_dir_exists'] else '✗ No'}")
297
293
 
298
294
  if global_status["needs_migration"]:
299
- console.print(f" [yellow]⚠ Migration needed[/yellow]")
295
+ console.print(" [yellow]⚠ Migration needed[/yellow]")
300
296
  console.print(f" Files to migrate: {len(global_status['files_to_migrate'])}")
301
297
  elif global_status["migration_done"]:
302
- console.print(f" [green]✓ Migration completed[/green]")
298
+ console.print(" [green]✓ Migration completed[/green]")
303
299
  else:
304
- console.print(f" [green]✓ No migration needed[/green]")
300
+ console.print(" [green]✓ No migration needed[/green]")
305
301
 
306
302
  # Show local status if in git repo
307
303
  if migration_status["local"]:
@@ -313,12 +309,12 @@ def migrate_command(dry_run: bool, force: bool, status: bool, scope: str):
313
309
  console.print(f" Exists: {'✓ Yes' if local_status['new_dir_exists'] else '✗ No'}")
314
310
 
315
311
  if local_status["needs_migration"]:
316
- console.print(f" [yellow]⚠ Migration needed[/yellow]")
312
+ console.print(" [yellow]⚠ Migration needed[/yellow]")
317
313
  console.print(f" Files to migrate: {len(local_status['files_to_migrate'])}")
318
314
  elif local_status["migration_done"]:
319
- console.print(f" [green]✓ Migration completed[/green]")
315
+ console.print(" [green]✓ Migration completed[/green]")
320
316
  else:
321
- console.print(f" [green]✓ No migration needed[/green]")
317
+ console.print(" [green]✓ No migration needed[/green]")
322
318
 
323
319
  # Show files to migrate if any
324
320
  all_files = global_status.get("files_to_migrate", [])
@@ -326,7 +322,7 @@ def migrate_command(dry_run: bool, force: bool, status: bool, scope: str):
326
322
  all_files.extend(migration_status["local"].get("files_to_migrate", []))
327
323
 
328
324
  if all_files:
329
- console.print(f"\n[bold]Files to migrate:[/bold]")
325
+ console.print("\n[bold]Files to migrate:[/bold]")
330
326
  table = Table()
331
327
  table.add_column("Location", style="cyan")
332
328
  table.add_column("File Name", style="yellow")
@@ -339,7 +335,7 @@ def migrate_command(dry_run: bool, force: bool, status: bool, scope: str):
339
335
  table.add_row("Local", filename)
340
336
 
341
337
  console.print(table)
342
- console.print(f"\n[dim]Run 'mcli self migrate' to perform migration[/dim]")
338
+ console.print("\n[dim]Run 'mcli self migrate' to perform migration[/dim]")
343
339
 
344
340
  return
345
341
 
@@ -356,19 +352,25 @@ def migrate_command(dry_run: bool, force: bool, status: bool, scope: str):
356
352
  console.print("\n[bold cyan]Migration Plan[/bold cyan]")
357
353
 
358
354
  if scope in ["global", "all"] and global_status["needs_migration"]:
359
- console.print(f"\n[bold]Global:[/bold]")
355
+ console.print("\n[bold]Global:[/bold]")
360
356
  console.print(f" Source: [cyan]{global_status['old_dir_path']}[/cyan]")
361
357
  console.print(f" Target: [cyan]{global_status['new_dir_path']}[/cyan]")
362
358
  console.print(f" Files: [yellow]{len(global_status['files_to_migrate'])}[/yellow]")
363
359
 
364
- if scope in ["local", "all"] and migration_status["local"] and migration_status["local"]["needs_migration"]:
365
- console.print(f"\n[bold]Local:[/bold]")
360
+ if (
361
+ scope in ["local", "all"]
362
+ and migration_status["local"]
363
+ and migration_status["local"]["needs_migration"]
364
+ ):
365
+ console.print("\n[bold]Local:[/bold]")
366
366
  console.print(f" Source: [cyan]{migration_status['local']['old_dir_path']}[/cyan]")
367
367
  console.print(f" Target: [cyan]{migration_status['local']['new_dir_path']}[/cyan]")
368
- console.print(f" Files: [yellow]{len(migration_status['local']['files_to_migrate'])}[/yellow]")
368
+ console.print(
369
+ f" Files: [yellow]{len(migration_status['local']['files_to_migrate'])}[/yellow]"
370
+ )
369
371
 
370
372
  if dry_run:
371
- console.print(f"\n[yellow]DRY RUN MODE - No changes will be made[/yellow]")
373
+ console.print("\n[yellow]DRY RUN MODE - No changes will be made[/yellow]")
372
374
 
373
375
  # Perform migration
374
376
  success_flag, message = migrate_commands_to_workflows(dry_run=dry_run, force=force, scope=scope)
mcli/self/redis_cmd.py CHANGED
@@ -14,13 +14,12 @@ logger = get_logger(__name__)
14
14
 
15
15
  @click.group(name="redis")
16
16
  def redis_group():
17
- """Manage Redis cache service"""
18
- pass
17
+ """Manage Redis cache service."""
19
18
 
20
19
 
21
20
  @redis_group.command(name="start")
22
21
  def start_redis():
23
- """Start Redis server"""
22
+ """Start Redis server."""
24
23
 
25
24
  async def _start():
26
25
  service = await get_redis_service()
@@ -51,7 +50,7 @@ def start_redis():
51
50
 
52
51
  @redis_group.command(name="stop")
53
52
  def stop_redis():
54
- """Stop Redis server"""
53
+ """Stop Redis server."""
55
54
 
56
55
  async def _stop():
57
56
  service = await get_redis_service()
@@ -73,7 +72,7 @@ def stop_redis():
73
72
 
74
73
  @redis_group.command(name="restart")
75
74
  def restart_redis():
76
- """Restart Redis server"""
75
+ """Restart Redis server."""
77
76
 
78
77
  async def _restart():
79
78
  service = await get_redis_service()
@@ -83,7 +82,7 @@ def restart_redis():
83
82
 
84
83
  if success:
85
84
  click.echo("✅ Redis server restarted successfully")
86
- status = await service.get_status()
85
+ await service.get_status()
87
86
  click.echo(f" Connection URL: {await service.get_connection_url()}")
88
87
  else:
89
88
  click.echo("❌ Failed to restart Redis server")
@@ -93,7 +92,7 @@ def restart_redis():
93
92
 
94
93
  @redis_group.command(name="status")
95
94
  def redis_status():
96
- """Show Redis server status"""
95
+ """Show Redis server status."""
97
96
 
98
97
  async def _status():
99
98
  service = await get_redis_service()
@@ -133,7 +132,7 @@ def redis_status():
133
132
 
134
133
  @redis_group.command(name="test")
135
134
  def test_redis():
136
- """Test Redis connection and performance"""
135
+ """Test Redis connection and performance."""
137
136
 
138
137
  async def _test():
139
138
  service = await get_redis_service()
@@ -162,7 +161,7 @@ def test_redis():
162
161
 
163
162
  @redis_group.command(name="info")
164
163
  def redis_info():
165
- """Show detailed Redis server information"""
164
+ """Show detailed Redis server information."""
166
165
 
167
166
  async def _info():
168
167
  service = await get_redis_service()
@@ -235,7 +234,7 @@ def redis_info():
235
234
  @redis_group.command(name="logs")
236
235
  @click.option("--lines", "-n", default=20, help="Number of log lines to show")
237
236
  def redis_logs(lines):
238
- """Show Redis server logs"""
237
+ """Show Redis server logs."""
239
238
 
240
239
  async def _logs():
241
240
  service = await get_redis_service()
@@ -265,5 +264,5 @@ def redis_logs(lines):
265
264
 
266
265
  # Register with main CLI
267
266
  def register_redis_commands(cli):
268
- """Register Redis commands with the main CLI"""
267
+ """Register Redis commands with the main CLI."""
269
268
  cli.add_command(redis_group)