mcli-framework 7.12.2__py3-none-any.whl → 7.12.4__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.
- mcli/app/__init__.py +0 -2
- mcli/app/commands_cmd.py +30 -26
- mcli/app/completion_helpers.py +5 -5
- mcli/app/init_cmd.py +10 -10
- mcli/app/lock_cmd.py +29 -24
- mcli/app/main.py +2 -8
- mcli/app/model/model.py +5 -10
- mcli/app/store_cmd.py +8 -8
- mcli/app/video/__init__.py +0 -2
- mcli/app/video/video.py +1 -14
- mcli/chat/chat.py +90 -108
- mcli/chat/command_rag.py +0 -4
- mcli/chat/enhanced_chat.py +32 -41
- mcli/chat/system_controller.py +37 -37
- mcli/chat/system_integration.py +4 -5
- mcli/cli.py +2 -3
- mcli/lib/api/api.py +4 -9
- mcli/lib/api/daemon_client.py +19 -20
- mcli/lib/api/daemon_client_local.py +1 -3
- mcli/lib/api/daemon_decorator.py +6 -6
- mcli/lib/api/mcli_decorators.py +4 -8
- mcli/lib/auth/__init__.py +0 -1
- mcli/lib/auth/auth.py +4 -5
- mcli/lib/auth/mcli_manager.py +7 -12
- mcli/lib/auth/token_util.py +5 -5
- mcli/lib/config/__init__.py +29 -1
- mcli/lib/config/config.py +0 -1
- mcli/lib/custom_commands.py +1 -1
- mcli/lib/discovery/command_discovery.py +15 -15
- mcli/lib/erd/erd.py +7 -7
- mcli/lib/files/files.py +1 -1
- mcli/lib/fs/__init__.py +31 -1
- mcli/lib/fs/fs.py +12 -13
- mcli/lib/lib.py +0 -1
- mcli/lib/logger/logger.py +7 -10
- mcli/lib/performance/optimizer.py +25 -27
- mcli/lib/performance/rust_bridge.py +22 -27
- mcli/lib/performance/uvloop_config.py +0 -1
- mcli/lib/pickles/__init__.py +0 -1
- mcli/lib/pickles/pickles.py +0 -2
- mcli/lib/secrets/commands.py +0 -2
- mcli/lib/secrets/manager.py +0 -1
- mcli/lib/secrets/repl.py +2 -3
- mcli/lib/secrets/store.py +1 -2
- mcli/lib/services/data_pipeline.py +34 -34
- mcli/lib/services/lsh_client.py +38 -40
- mcli/lib/shell/shell.py +2 -2
- mcli/lib/toml/__init__.py +0 -1
- mcli/lib/ui/styling.py +0 -1
- mcli/lib/ui/visual_effects.py +33 -41
- mcli/lib/watcher/watcher.py +0 -1
- mcli/ml/__init__.py +1 -1
- mcli/ml/api/__init__.py +1 -1
- mcli/ml/api/app.py +8 -9
- mcli/ml/api/middleware.py +10 -10
- mcli/ml/api/routers/__init__.py +1 -1
- mcli/ml/api/routers/admin_router.py +3 -3
- mcli/ml/api/routers/auth_router.py +17 -18
- mcli/ml/api/routers/backtest_router.py +2 -2
- mcli/ml/api/routers/data_router.py +2 -2
- mcli/ml/api/routers/model_router.py +14 -15
- mcli/ml/api/routers/monitoring_router.py +2 -2
- mcli/ml/api/routers/portfolio_router.py +2 -2
- mcli/ml/api/routers/prediction_router.py +10 -9
- mcli/ml/api/routers/trade_router.py +2 -2
- mcli/ml/api/routers/websocket_router.py +6 -7
- mcli/ml/api/schemas.py +2 -2
- mcli/ml/auth/__init__.py +1 -1
- mcli/ml/auth/auth_manager.py +22 -23
- mcli/ml/auth/models.py +17 -17
- mcli/ml/auth/permissions.py +17 -17
- mcli/ml/backtesting/__init__.py +1 -1
- mcli/ml/backtesting/backtest_engine.py +31 -35
- mcli/ml/backtesting/performance_metrics.py +12 -14
- mcli/ml/backtesting/run.py +1 -2
- mcli/ml/cache.py +35 -36
- mcli/ml/cli/__init__.py +1 -1
- mcli/ml/cli/main.py +21 -24
- mcli/ml/config/__init__.py +1 -1
- mcli/ml/config/settings.py +28 -29
- mcli/ml/configs/__init__.py +1 -1
- mcli/ml/configs/dvc_config.py +14 -15
- mcli/ml/configs/mlflow_config.py +12 -13
- mcli/ml/configs/mlops_manager.py +19 -21
- mcli/ml/dashboard/__init__.py +4 -4
- mcli/ml/dashboard/app.py +20 -30
- mcli/ml/dashboard/app_supabase.py +16 -19
- mcli/ml/dashboard/app_training.py +11 -14
- mcli/ml/dashboard/cli.py +2 -2
- mcli/ml/dashboard/common.py +2 -3
- mcli/ml/dashboard/components/__init__.py +1 -1
- mcli/ml/dashboard/components/charts.py +13 -11
- mcli/ml/dashboard/components/metrics.py +7 -7
- mcli/ml/dashboard/components/tables.py +12 -9
- mcli/ml/dashboard/overview.py +2 -2
- mcli/ml/dashboard/pages/__init__.py +1 -1
- mcli/ml/dashboard/pages/cicd.py +15 -18
- mcli/ml/dashboard/pages/debug_dependencies.py +7 -7
- mcli/ml/dashboard/pages/monte_carlo_predictions.py +11 -18
- mcli/ml/dashboard/pages/predictions_enhanced.py +24 -32
- mcli/ml/dashboard/pages/scrapers_and_logs.py +22 -24
- mcli/ml/dashboard/pages/test_portfolio.py +3 -6
- mcli/ml/dashboard/pages/trading.py +16 -18
- mcli/ml/dashboard/pages/workflows.py +20 -30
- mcli/ml/dashboard/utils.py +9 -9
- mcli/ml/dashboard/warning_suppression.py +3 -3
- mcli/ml/data_ingestion/__init__.py +1 -1
- mcli/ml/data_ingestion/api_connectors.py +41 -46
- mcli/ml/data_ingestion/data_pipeline.py +36 -46
- mcli/ml/data_ingestion/stream_processor.py +43 -46
- mcli/ml/database/__init__.py +1 -1
- mcli/ml/database/migrations/env.py +2 -2
- mcli/ml/database/models.py +22 -24
- mcli/ml/database/session.py +14 -14
- mcli/ml/experimentation/__init__.py +1 -1
- mcli/ml/experimentation/ab_testing.py +45 -46
- mcli/ml/features/__init__.py +1 -1
- mcli/ml/features/ensemble_features.py +22 -27
- mcli/ml/features/recommendation_engine.py +30 -30
- mcli/ml/features/stock_features.py +29 -32
- mcli/ml/features/test_feature_engineering.py +10 -11
- mcli/ml/logging.py +4 -4
- mcli/ml/mlops/__init__.py +1 -1
- mcli/ml/mlops/data_versioning.py +29 -30
- mcli/ml/mlops/experiment_tracker.py +24 -24
- mcli/ml/mlops/model_serving.py +31 -34
- mcli/ml/mlops/pipeline_orchestrator.py +27 -35
- mcli/ml/models/__init__.py +5 -6
- mcli/ml/models/base_models.py +23 -23
- mcli/ml/models/ensemble_models.py +31 -31
- mcli/ml/models/recommendation_models.py +18 -19
- mcli/ml/models/test_models.py +14 -16
- mcli/ml/monitoring/__init__.py +1 -1
- mcli/ml/monitoring/drift_detection.py +32 -36
- mcli/ml/monitoring/metrics.py +2 -2
- mcli/ml/optimization/__init__.py +1 -1
- mcli/ml/optimization/optimize.py +1 -2
- mcli/ml/optimization/portfolio_optimizer.py +30 -32
- mcli/ml/predictions/__init__.py +1 -1
- mcli/ml/preprocessing/__init__.py +1 -1
- mcli/ml/preprocessing/data_cleaners.py +22 -23
- mcli/ml/preprocessing/feature_extractors.py +23 -26
- mcli/ml/preprocessing/ml_pipeline.py +23 -23
- mcli/ml/preprocessing/test_preprocessing.py +7 -8
- mcli/ml/scripts/populate_sample_data.py +0 -4
- mcli/ml/serving/serve.py +1 -2
- mcli/ml/tasks.py +17 -17
- mcli/ml/tests/test_integration.py +29 -30
- mcli/ml/tests/test_training_dashboard.py +21 -21
- mcli/ml/trading/__init__.py +1 -1
- mcli/ml/trading/migrations.py +5 -5
- mcli/ml/trading/models.py +21 -23
- mcli/ml/trading/paper_trading.py +16 -13
- mcli/ml/trading/risk_management.py +17 -18
- mcli/ml/trading/trading_service.py +25 -28
- mcli/ml/training/__init__.py +1 -1
- mcli/ml/training/train.py +0 -1
- mcli/public/oi/oi.py +1 -2
- mcli/self/completion_cmd.py +6 -10
- mcli/self/logs_cmd.py +19 -24
- mcli/self/migrate_cmd.py +22 -20
- mcli/self/redis_cmd.py +10 -11
- mcli/self/self_cmd.py +10 -18
- mcli/self/store_cmd.py +10 -12
- mcli/self/visual_cmd.py +9 -14
- mcli/self/zsh_cmd.py +2 -4
- mcli/workflow/daemon/async_command_database.py +23 -24
- mcli/workflow/daemon/async_process_manager.py +27 -29
- mcli/workflow/daemon/client.py +27 -33
- mcli/workflow/daemon/daemon.py +32 -36
- mcli/workflow/daemon/enhanced_daemon.py +24 -33
- mcli/workflow/daemon/process_cli.py +11 -12
- mcli/workflow/daemon/process_manager.py +23 -26
- mcli/workflow/daemon/test_daemon.py +4 -5
- mcli/workflow/dashboard/dashboard_cmd.py +0 -1
- mcli/workflow/doc_convert.py +15 -17
- mcli/workflow/gcloud/__init__.py +0 -1
- mcli/workflow/gcloud/gcloud.py +11 -8
- mcli/workflow/git_commit/ai_service.py +14 -15
- mcli/workflow/lsh_integration.py +9 -11
- mcli/workflow/model_service/client.py +26 -31
- mcli/workflow/model_service/download_and_run_efficient_models.py +10 -14
- mcli/workflow/model_service/lightweight_embedder.py +25 -35
- mcli/workflow/model_service/lightweight_model_server.py +26 -32
- mcli/workflow/model_service/lightweight_test.py +7 -10
- mcli/workflow/model_service/model_service.py +80 -91
- mcli/workflow/model_service/ollama_efficient_runner.py +14 -18
- mcli/workflow/model_service/openai_adapter.py +23 -23
- mcli/workflow/model_service/pdf_processor.py +21 -26
- mcli/workflow/model_service/test_efficient_runner.py +12 -16
- mcli/workflow/model_service/test_example.py +11 -13
- mcli/workflow/model_service/test_integration.py +3 -5
- mcli/workflow/model_service/test_new_features.py +7 -8
- mcli/workflow/notebook/converter.py +1 -1
- mcli/workflow/notebook/notebook_cmd.py +5 -6
- mcli/workflow/notebook/schema.py +0 -1
- mcli/workflow/notebook/validator.py +7 -3
- mcli/workflow/openai/openai.py +1 -2
- mcli/workflow/registry/registry.py +4 -1
- mcli/workflow/repo/repo.py +6 -7
- mcli/workflow/scheduler/cron_parser.py +16 -19
- mcli/workflow/scheduler/job.py +10 -10
- mcli/workflow/scheduler/monitor.py +15 -15
- mcli/workflow/scheduler/persistence.py +17 -18
- mcli/workflow/scheduler/scheduler.py +37 -38
- mcli/workflow/secrets/__init__.py +1 -1
- mcli/workflow/sync/test_cmd.py +0 -1
- mcli/workflow/wakatime/__init__.py +5 -9
- mcli/workflow/wakatime/wakatime.py +1 -2
- {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/METADATA +1 -1
- mcli_framework-7.12.4.dist-info/RECORD +279 -0
- mcli_framework-7.12.2.dist-info/RECORD +0 -279
- {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/WHEEL +0 -0
- {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/entry_points.txt +0 -0
- {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.dist-info}/licenses/LICENSE +0 -0
- {mcli_framework-7.12.2.dist-info → mcli_framework-7.12.4.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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 {}
|
mcli/ml/training/__init__.py
CHANGED
mcli/ml/training/train.py
CHANGED
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__":
|
mcli/self/completion_cmd.py
CHANGED
|
@@ -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(
|
|
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(
|
|
38
|
+
console.print(" [yellow]⚠ Directory exists but no log files yet[/yellow]")
|
|
44
39
|
else:
|
|
45
|
-
console.print(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
298
|
+
console.print(" [green]✓ Migration completed[/green]")
|
|
303
299
|
else:
|
|
304
|
-
console.print(
|
|
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(
|
|
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(
|
|
315
|
+
console.print(" [green]✓ Migration completed[/green]")
|
|
320
316
|
else:
|
|
321
|
-
console.print(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
365
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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)
|