mcli-framework 7.0.1__tar.gz → 7.0.5__tar.gz
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_framework-7.0.1 → mcli_framework-7.0.5}/PKG-INFO +1 -1
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/pyproject.toml +1 -1
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/completion_helpers.py +6 -2
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/model_cmd.py +102 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/self/self_cmd.py +63 -9
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/lightweight_model_server.py +37 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli_framework.egg-info/PKG-INFO +1 -1
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli_framework.egg-info/SOURCES.txt +1 -0
- mcli_framework-7.0.5/tests/test_model_cmd.py +362 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_self.py +32 -1
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/dependabot.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/build.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/ci.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/ml-pipeline.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/publish-self-hosted.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/publish.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/release.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/security.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/.github/workflows/test.yml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/LICENSE +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/MANIFEST.in +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/PERFORMANCE_OPTIMIZATIONS.md +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/README.md +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/mcli_rust/Cargo.toml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/mcli_rust/src/command_parser.rs +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/mcli_rust/src/file_watcher.rs +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/mcli_rust/src/lib.rs +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/mcli_rust/src/process_manager.rs +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/mcli_rust/src/tfidf.rs +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/setup.cfg +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/chat_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/commands_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/completion_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/cron_test_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/logs_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/main.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/model/model.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/redis_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/video/video.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/app/visual_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/chat/chat.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/chat/command_rag.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/chat/enhanced_chat.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/chat/system_controller.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/chat/system_integration.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/cli.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/config.toml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/api/api.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/api/daemon_client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/api/daemon_client_local.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/api/daemon_decorator.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/api/mcli_decorators.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/auth.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/aws_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/azure_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/credential_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/gcp_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/key_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/mcli_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/token_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/auth/token_util.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/config/config.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/discovery/__init__.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/discovery/command_discovery.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/erd/erd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/erd/generate_graph.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/files/files.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/fs/fs.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/lib.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/logger/logger.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/paths.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/performance/optimizer.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/performance/rust_bridge.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/performance/uvloop_config.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/pickles/pickles.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/search/cached_vectorizer.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/services/data_pipeline.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/services/lsh_client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/services/redis_service.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/shell/shell.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/toml/toml.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/ui/styling.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/ui/visual_effects.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/lib/watcher/watcher.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/app.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/middleware.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/admin_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/auth_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/backtest_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/data_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/model_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/monitoring_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/portfolio_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/prediction_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/trade_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/routers/websocket_router.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/api/schemas.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/auth/auth_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/auth/models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/auth/permissions.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/backtesting/backtest_engine.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/backtesting/performance_metrics.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/cache.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/cli/main.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/config/settings.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/configs/dvc_config.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/configs/mlflow_config.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/configs/mlops_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/dashboard/app.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/dashboard/app_integrated.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/dashboard/app_supabase.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/dashboard/app_training.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/dashboard/cli.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/data_ingestion/api_connectors.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/data_ingestion/data_pipeline.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/data_ingestion/stream_processor.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/database/migrations/env.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/database/models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/database/session.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/experimentation/ab_testing.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/features/ensemble_features.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/features/political_features.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/features/recommendation_engine.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/features/stock_features.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/features/test_feature_engineering.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/logging.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/mlops/data_versioning.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/mlops/experiment_tracker.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/mlops/model_serving.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/mlops/pipeline_orchestrator.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/models/base_models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/models/ensemble_models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/models/recommendation_models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/models/test_models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/monitoring/drift_detection.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/monitoring/metrics.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/optimization/portfolio_optimizer.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/preprocessing/data_cleaners.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/preprocessing/feature_extractors.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/preprocessing/ml_pipeline.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/preprocessing/politician_trading_preprocessor.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/preprocessing/test_preprocessing.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/scripts/populate_sample_data.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/tasks.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/tests/test_integration.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/ml/tests/test_training_dashboard.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/public/oi/oi.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/public/public.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/api_daemon.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/async_command_database.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/async_process_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/commands.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/daemon.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/daemon_api.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/enhanced_daemon.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/process_cli.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/process_manager.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/daemon/test_daemon.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/dashboard/dashboard_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/docker/docker.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/file/file.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/gcloud/config.toml +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/gcloud/gcloud.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/git_commit/ai_service.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/git_commit/commands.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/lsh_integration.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/download_and_run_efficient_models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/lightweight_embedder.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/lightweight_test.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/model_service.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/ollama_efficient_runner.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/pdf_processor.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/test_efficient_runner.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/test_example.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/test_integration.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/model_service/test_new_features.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/openai/openai.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/commands.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/config.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/connectivity.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/data_sources.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/database.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/demo.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/monitoring.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/scrapers.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/scrapers_california.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/scrapers_eu.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/scrapers_uk.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/scrapers_us_states.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/supabase_functions.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/politician_trading/workflow.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/registry/registry.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/repo/repo.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/scheduler/commands.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/scheduler/cron_parser.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/scheduler/job.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/scheduler/monitor.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/scheduler/persistence.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/scheduler/scheduler.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/sync/sync_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/sync/test_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/videos/videos.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/wakatime/wakatime.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli/workflow/workflow.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli_framework.egg-info/dependency_links.txt +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli_framework.egg-info/entry_points.txt +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli_framework.egg-info/requires.txt +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/src/mcli_framework.egg-info/top_level.txt +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/conftest.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/demo_generate_graph.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/demo_hierarchical_transform.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/end_to_end_integration_test.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/pytest.ini +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/run_tests.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/simple_integration_test.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_agent_functionality.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_all_cli.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_auth.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_california_scraper.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_chat_client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_chat_cmd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_chat_system_control.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_command_discovery.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_congress_scraper.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_daemon.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_daemon_client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_data_pipeline.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_enhanced_chat.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_erd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_erd_import.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_file.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_fix.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_fixed_issues.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_gcloud.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_generate_graph.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_generic_erd.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_harness.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_lib.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_lsh_client.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_lsh_integration.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_main_app.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_main_app_functions.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_ml_auth.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_ml_models.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_ml_pipeline.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_oi.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_optional_dependencies.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_politician_trading_integration.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_preprocessing_simple.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_registry.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_repo.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_rich.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_uk_scraper.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_us_states_scraper.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_utility_functions.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_utility_functions_simple.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_uv_compatibility.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_videos.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_wakatime.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_webapp.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_webapp_comprehensive.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_workflow.py +0 -0
- {mcli_framework-7.0.1 → mcli_framework-7.0.5}/tests/test_workflow_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcli-framework
|
|
3
|
-
Version: 7.0.
|
|
3
|
+
Version: 7.0.5
|
|
4
4
|
Summary: 🚀 High-performance CLI framework with Rust extensions, AI chat, and stunning visuals
|
|
5
5
|
Author-email: Luis Fernandez de la Vara <luis@lefv.io>
|
|
6
6
|
Maintainer-email: Luis Fernandez de la Vara <luis@lefv.io>
|
|
@@ -7,6 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Optional
|
|
8
8
|
|
|
9
9
|
import click
|
|
10
|
+
import psutil
|
|
10
11
|
|
|
11
12
|
from mcli.lib.logger.logger import get_logger
|
|
12
13
|
from mcli.workflow.model_service.lightweight_model_server import (
|
|
@@ -223,5 +224,106 @@ def status(port: int):
|
|
|
223
224
|
click.echo(f"❌ Error checking server: {e}")
|
|
224
225
|
|
|
225
226
|
|
|
227
|
+
@model.command()
|
|
228
|
+
@click.option("--port", "-p", default=8080, help="Port where server is running")
|
|
229
|
+
def stop(port: int):
|
|
230
|
+
"""Stop the lightweight model server."""
|
|
231
|
+
import requests
|
|
232
|
+
import psutil
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
# First check if server is running
|
|
236
|
+
try:
|
|
237
|
+
response = requests.get(f"http://localhost:{port}/health", timeout=2)
|
|
238
|
+
if response.status_code != 200:
|
|
239
|
+
click.echo(f"❌ No server running on port {port}")
|
|
240
|
+
return
|
|
241
|
+
except requests.exceptions.ConnectionError:
|
|
242
|
+
click.echo(f"❌ No server running on port {port}")
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
# Find and kill the process using the port
|
|
246
|
+
for proc in psutil.process_iter(["pid", "name", "connections"]):
|
|
247
|
+
try:
|
|
248
|
+
connections = proc.info.get("connections")
|
|
249
|
+
if connections:
|
|
250
|
+
for conn in connections:
|
|
251
|
+
if hasattr(conn, "laddr") and conn.laddr.port == port:
|
|
252
|
+
click.echo(f"🛑 Stopping server (PID: {proc.pid})...")
|
|
253
|
+
proc.terminate()
|
|
254
|
+
proc.wait(timeout=5)
|
|
255
|
+
click.echo("✅ Server stopped successfully")
|
|
256
|
+
return
|
|
257
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired):
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
click.echo("⚠️ Could not find server process")
|
|
261
|
+
|
|
262
|
+
except Exception as e:
|
|
263
|
+
click.echo(f"❌ Error stopping server: {e}")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@model.command()
|
|
267
|
+
@click.argument("model_name")
|
|
268
|
+
def pull(model_name: str):
|
|
269
|
+
"""Pull (download) a specific lightweight model."""
|
|
270
|
+
if model_name not in LIGHTWEIGHT_MODELS:
|
|
271
|
+
click.echo(f"❌ Model '{model_name}' not found.")
|
|
272
|
+
click.echo("Available models:")
|
|
273
|
+
for key in LIGHTWEIGHT_MODELS.keys():
|
|
274
|
+
click.echo(f" • {key}")
|
|
275
|
+
sys.exit(1)
|
|
276
|
+
|
|
277
|
+
server = LightweightModelServer()
|
|
278
|
+
|
|
279
|
+
click.echo(f"Pulling model: {model_name}")
|
|
280
|
+
success = server.download_and_load_model(model_name)
|
|
281
|
+
|
|
282
|
+
if success:
|
|
283
|
+
click.echo(f"✅ Successfully pulled {model_name}")
|
|
284
|
+
else:
|
|
285
|
+
click.echo(f"❌ Failed to pull {model_name}")
|
|
286
|
+
sys.exit(1)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@model.command()
|
|
290
|
+
@click.argument("model_name")
|
|
291
|
+
@click.option("--force", "-f", is_flag=True, help="Force deletion without confirmation")
|
|
292
|
+
def delete(model_name: str, force: bool):
|
|
293
|
+
"""Delete a downloaded lightweight model."""
|
|
294
|
+
server = LightweightModelServer()
|
|
295
|
+
downloaded_models = server.downloader.get_downloaded_models()
|
|
296
|
+
|
|
297
|
+
if model_name not in downloaded_models:
|
|
298
|
+
click.echo(f"❌ Model '{model_name}' not found.")
|
|
299
|
+
click.echo("Downloaded models:")
|
|
300
|
+
if downloaded_models:
|
|
301
|
+
for model in downloaded_models:
|
|
302
|
+
click.echo(f" • {model}")
|
|
303
|
+
else:
|
|
304
|
+
click.echo(" (none)")
|
|
305
|
+
sys.exit(1)
|
|
306
|
+
|
|
307
|
+
# Confirm deletion unless --force is used
|
|
308
|
+
if not force:
|
|
309
|
+
model_info = LIGHTWEIGHT_MODELS.get(model_name, {})
|
|
310
|
+
name = model_info.get("name", model_name)
|
|
311
|
+
size = model_info.get("size_mb", "unknown")
|
|
312
|
+
click.echo(f"⚠️ About to delete:")
|
|
313
|
+
click.echo(f" Model: {name}")
|
|
314
|
+
click.echo(f" Size: {size} MB")
|
|
315
|
+
if not click.confirm("Are you sure you want to delete this model?"):
|
|
316
|
+
click.echo("❌ Deletion cancelled")
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
success = server.delete_model(model_name)
|
|
320
|
+
|
|
321
|
+
if success:
|
|
322
|
+
click.echo(f"✅ Successfully deleted {model_name}")
|
|
323
|
+
else:
|
|
324
|
+
click.echo(f"❌ Failed to delete {model_name}")
|
|
325
|
+
sys.exit(1)
|
|
326
|
+
|
|
327
|
+
|
|
226
328
|
if __name__ == "__main__":
|
|
227
329
|
model()
|
|
@@ -774,18 +774,15 @@ def logs(type: str, lines: int, follow: bool, date: str, grep: str, level: str):
|
|
|
774
774
|
from datetime import datetime
|
|
775
775
|
from pathlib import Path
|
|
776
776
|
|
|
777
|
-
#
|
|
778
|
-
|
|
779
|
-
# Go up 5 levels: file -> self -> mcli -> src -> repo_root
|
|
780
|
-
project_root = current_file.parents[4]
|
|
781
|
-
logs_dir = project_root / "logs"
|
|
777
|
+
# Import get_logs_dir to get the correct logs directory
|
|
778
|
+
from mcli.lib.paths import get_logs_dir
|
|
782
779
|
|
|
783
|
-
#
|
|
784
|
-
|
|
785
|
-
logs_dir = Path.cwd() / "logs"
|
|
780
|
+
# Get the logs directory (creates it if it doesn't exist)
|
|
781
|
+
logs_dir = get_logs_dir()
|
|
786
782
|
|
|
787
783
|
if not logs_dir.exists():
|
|
788
784
|
click.echo("❌ Logs directory not found", err=True)
|
|
785
|
+
click.echo(f"Expected location: {logs_dir}", err=True)
|
|
789
786
|
return
|
|
790
787
|
|
|
791
788
|
# Determine which log files to read
|
|
@@ -1129,11 +1126,53 @@ def dashboard(refresh: float, once: bool):
|
|
|
1129
1126
|
console.print(f"[red]Error launching dashboard: {e}[/red]")
|
|
1130
1127
|
|
|
1131
1128
|
|
|
1129
|
+
def check_ci_status(version: str) -> tuple[bool, Optional[str]]:
|
|
1130
|
+
"""
|
|
1131
|
+
Check GitHub Actions CI status for the main branch.
|
|
1132
|
+
Returns (passing, url) tuple.
|
|
1133
|
+
"""
|
|
1134
|
+
try:
|
|
1135
|
+
import requests
|
|
1136
|
+
|
|
1137
|
+
response = requests.get(
|
|
1138
|
+
"https://api.github.com/repos/gwicho38/mcli/actions/runs",
|
|
1139
|
+
params={"per_page": 5},
|
|
1140
|
+
headers={
|
|
1141
|
+
"Accept": "application/vnd.github.v3+json",
|
|
1142
|
+
"User-Agent": "mcli-cli"
|
|
1143
|
+
},
|
|
1144
|
+
timeout=10
|
|
1145
|
+
)
|
|
1146
|
+
|
|
1147
|
+
if response.status_code == 200:
|
|
1148
|
+
data = response.json()
|
|
1149
|
+
runs = data.get("workflow_runs", [])
|
|
1150
|
+
|
|
1151
|
+
# Find the most recent completed run for main branch
|
|
1152
|
+
main_runs = [
|
|
1153
|
+
run for run in runs
|
|
1154
|
+
if run.get("head_branch") == "main" and run.get("status") == "completed"
|
|
1155
|
+
]
|
|
1156
|
+
|
|
1157
|
+
if main_runs:
|
|
1158
|
+
latest_run = main_runs[0]
|
|
1159
|
+
passing = latest_run.get("conclusion") == "success"
|
|
1160
|
+
url = latest_run.get("html_url")
|
|
1161
|
+
return (passing, url)
|
|
1162
|
+
|
|
1163
|
+
# If we can't check CI, don't block the update
|
|
1164
|
+
return (True, None)
|
|
1165
|
+
except Exception:
|
|
1166
|
+
# On error, don't block the update
|
|
1167
|
+
return (True, None)
|
|
1168
|
+
|
|
1169
|
+
|
|
1132
1170
|
@self_app.command()
|
|
1133
1171
|
@click.option("--check", is_flag=True, help="Only check for updates, don't install")
|
|
1134
1172
|
@click.option("--pre", is_flag=True, help="Include pre-release versions")
|
|
1135
1173
|
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
|
|
1136
|
-
|
|
1174
|
+
@click.option("--skip-ci-check", is_flag=True, help="Skip CI status check and install anyway")
|
|
1175
|
+
def update(check: bool, pre: bool, yes: bool, skip_ci_check: bool):
|
|
1137
1176
|
"""🔄 Check for and install mcli updates from PyPI"""
|
|
1138
1177
|
import subprocess
|
|
1139
1178
|
import sys
|
|
@@ -1215,6 +1254,21 @@ def update(check: bool, pre: bool, yes: bool):
|
|
|
1215
1254
|
console.print("[yellow]Update cancelled[/yellow]")
|
|
1216
1255
|
return
|
|
1217
1256
|
|
|
1257
|
+
# Check CI status before installing (unless skipped)
|
|
1258
|
+
if not skip_ci_check:
|
|
1259
|
+
console.print("[cyan]🔍 Checking CI status...[/cyan]")
|
|
1260
|
+
ci_passing, ci_url = check_ci_status(latest_version)
|
|
1261
|
+
|
|
1262
|
+
if not ci_passing:
|
|
1263
|
+
console.print("[red]✗ CI build is failing for the latest version[/red]")
|
|
1264
|
+
if ci_url:
|
|
1265
|
+
console.print(f"[yellow] View CI status: {ci_url}[/yellow]")
|
|
1266
|
+
console.print("[yellow]⚠️ Update blocked to prevent installing a broken version[/yellow]")
|
|
1267
|
+
console.print("[dim] Use --skip-ci-check to install anyway (not recommended)[/dim]")
|
|
1268
|
+
return
|
|
1269
|
+
else:
|
|
1270
|
+
console.print("[green]✓ CI build is passing[/green]")
|
|
1271
|
+
|
|
1218
1272
|
# Install update
|
|
1219
1273
|
console.print(f"[cyan]📦 Installing mcli {latest_version}...[/cyan]")
|
|
1220
1274
|
|
|
@@ -566,6 +566,43 @@ class LightweightModelServer:
|
|
|
566
566
|
else:
|
|
567
567
|
return "distilbert-base-uncased" # Standard small model
|
|
568
568
|
|
|
569
|
+
def stop_server(self) -> bool:
|
|
570
|
+
"""Stop the lightweight server"""
|
|
571
|
+
if not self.running:
|
|
572
|
+
print("⚠️ Server is not running")
|
|
573
|
+
return False
|
|
574
|
+
|
|
575
|
+
try:
|
|
576
|
+
self.running = False
|
|
577
|
+
print("🛑 Server stopped")
|
|
578
|
+
return True
|
|
579
|
+
except Exception as e:
|
|
580
|
+
print(f"❌ Error stopping server: {e}")
|
|
581
|
+
return False
|
|
582
|
+
|
|
583
|
+
def delete_model(self, model_key: str) -> bool:
|
|
584
|
+
"""Delete a downloaded model"""
|
|
585
|
+
try:
|
|
586
|
+
model_dir = self.models_dir / model_key
|
|
587
|
+
|
|
588
|
+
if not model_dir.exists():
|
|
589
|
+
print(f"⚠️ Model '{model_key}' not found")
|
|
590
|
+
return False
|
|
591
|
+
|
|
592
|
+
# Remove from loaded models if present
|
|
593
|
+
if model_key in self.loaded_models:
|
|
594
|
+
del self.loaded_models[model_key]
|
|
595
|
+
print(f"✅ Unloaded model: {model_key}")
|
|
596
|
+
|
|
597
|
+
# Delete the model directory
|
|
598
|
+
shutil.rmtree(model_dir)
|
|
599
|
+
print(f"✅ Deleted model: {model_key}")
|
|
600
|
+
return True
|
|
601
|
+
|
|
602
|
+
except Exception as e:
|
|
603
|
+
print(f"❌ Error deleting model {model_key}: {e}")
|
|
604
|
+
return False
|
|
605
|
+
|
|
569
606
|
|
|
570
607
|
def create_simple_client():
|
|
571
608
|
"""Create a simple client script for testing"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcli-framework
|
|
3
|
-
Version: 7.0.
|
|
3
|
+
Version: 7.0.5
|
|
4
4
|
Summary: 🚀 High-performance CLI framework with Rust extensions, AI chat, and stunning visuals
|
|
5
5
|
Author-email: Luis Fernandez de la Vara <luis@lefv.io>
|
|
6
6
|
Maintainer-email: Luis Fernandez de la Vara <luis@lefv.io>
|
|
@@ -243,6 +243,7 @@ tests/test_main_app_functions.py
|
|
|
243
243
|
tests/test_ml_auth.py
|
|
244
244
|
tests/test_ml_models.py
|
|
245
245
|
tests/test_ml_pipeline.py
|
|
246
|
+
tests/test_model_cmd.py
|
|
246
247
|
tests/test_oi.py
|
|
247
248
|
tests/test_optional_dependencies.py
|
|
248
249
|
tests/test_politician_trading_integration.py
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for mcli.app.model_cmd module
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from unittest.mock import Mock, patch, MagicMock
|
|
7
|
+
from click.testing import CliRunner
|
|
8
|
+
|
|
9
|
+
from mcli.app.model_cmd import model, list, download, start, stop, pull, delete, recommend, status
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestModelCommands:
|
|
13
|
+
"""Test suite for model command functionality"""
|
|
14
|
+
|
|
15
|
+
def setup_method(self):
|
|
16
|
+
"""Setup test environment"""
|
|
17
|
+
self.runner = CliRunner()
|
|
18
|
+
|
|
19
|
+
def test_model_group_exists(self):
|
|
20
|
+
"""Test that model command group is properly defined"""
|
|
21
|
+
assert model is not None
|
|
22
|
+
assert hasattr(model, 'commands')
|
|
23
|
+
assert model.name == 'model'
|
|
24
|
+
|
|
25
|
+
def test_list_command_exists(self):
|
|
26
|
+
"""Test that list command is properly defined"""
|
|
27
|
+
assert list is not None
|
|
28
|
+
assert list.name == 'list'
|
|
29
|
+
|
|
30
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
31
|
+
def test_list_command_basic(self, mock_server_class):
|
|
32
|
+
"""Test list command basic functionality"""
|
|
33
|
+
mock_server = Mock()
|
|
34
|
+
mock_server_class.return_value = mock_server
|
|
35
|
+
mock_server.downloader.get_downloaded_models.return_value = []
|
|
36
|
+
mock_server.get_system_info.return_value = {
|
|
37
|
+
'cpu_count': 4,
|
|
38
|
+
'memory_gb': 8.0,
|
|
39
|
+
'disk_free_gb': 100.0
|
|
40
|
+
}
|
|
41
|
+
mock_server.recommend_model.return_value = "distilbert-base-uncased"
|
|
42
|
+
|
|
43
|
+
result = self.runner.invoke(model, ['list'])
|
|
44
|
+
|
|
45
|
+
assert result.exit_code == 0
|
|
46
|
+
assert 'Available Lightweight Models' in result.output
|
|
47
|
+
|
|
48
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
49
|
+
def test_download_command_success(self, mock_server_class):
|
|
50
|
+
"""Test download command with successful download"""
|
|
51
|
+
mock_server = Mock()
|
|
52
|
+
mock_server_class.return_value = mock_server
|
|
53
|
+
mock_server.download_and_load_model.return_value = True
|
|
54
|
+
|
|
55
|
+
result = self.runner.invoke(model, ['download', 'distilbert-base-uncased'])
|
|
56
|
+
|
|
57
|
+
assert result.exit_code == 0
|
|
58
|
+
assert 'Successfully downloaded' in result.output
|
|
59
|
+
mock_server.download_and_load_model.assert_called_once_with('distilbert-base-uncased')
|
|
60
|
+
|
|
61
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
62
|
+
def test_download_command_failure(self, mock_server_class):
|
|
63
|
+
"""Test download command with failed download"""
|
|
64
|
+
mock_server = Mock()
|
|
65
|
+
mock_server_class.return_value = mock_server
|
|
66
|
+
mock_server.download_and_load_model.return_value = False
|
|
67
|
+
|
|
68
|
+
result = self.runner.invoke(model, ['download', 'distilbert-base-uncased'])
|
|
69
|
+
|
|
70
|
+
assert result.exit_code == 1
|
|
71
|
+
assert 'Failed to download' in result.output
|
|
72
|
+
|
|
73
|
+
def test_download_command_invalid_model(self):
|
|
74
|
+
"""Test download command with invalid model name"""
|
|
75
|
+
result = self.runner.invoke(model, ['download', 'invalid-model-name'])
|
|
76
|
+
|
|
77
|
+
assert result.exit_code == 1
|
|
78
|
+
assert 'not found' in result.output
|
|
79
|
+
|
|
80
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
81
|
+
def test_pull_command_success(self, mock_server_class):
|
|
82
|
+
"""Test pull command with successful pull"""
|
|
83
|
+
mock_server = Mock()
|
|
84
|
+
mock_server_class.return_value = mock_server
|
|
85
|
+
mock_server.download_and_load_model.return_value = True
|
|
86
|
+
|
|
87
|
+
result = self.runner.invoke(model, ['pull', 'distilbert-base-uncased'])
|
|
88
|
+
|
|
89
|
+
assert result.exit_code == 0
|
|
90
|
+
assert 'Successfully pulled' in result.output
|
|
91
|
+
mock_server.download_and_load_model.assert_called_once_with('distilbert-base-uncased')
|
|
92
|
+
|
|
93
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
94
|
+
def test_pull_command_failure(self, mock_server_class):
|
|
95
|
+
"""Test pull command with failed pull"""
|
|
96
|
+
mock_server = Mock()
|
|
97
|
+
mock_server_class.return_value = mock_server
|
|
98
|
+
mock_server.download_and_load_model.return_value = False
|
|
99
|
+
|
|
100
|
+
result = self.runner.invoke(model, ['pull', 'distilbert-base-uncased'])
|
|
101
|
+
|
|
102
|
+
assert result.exit_code == 1
|
|
103
|
+
assert 'Failed to pull' in result.output
|
|
104
|
+
|
|
105
|
+
def test_pull_command_invalid_model(self):
|
|
106
|
+
"""Test pull command with invalid model name"""
|
|
107
|
+
result = self.runner.invoke(model, ['pull', 'invalid-model-name'])
|
|
108
|
+
|
|
109
|
+
assert result.exit_code == 1
|
|
110
|
+
assert 'not found' in result.output
|
|
111
|
+
|
|
112
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
113
|
+
def test_delete_command_success_with_force(self, mock_server_class):
|
|
114
|
+
"""Test delete command with successful deletion using force flag"""
|
|
115
|
+
mock_server = Mock()
|
|
116
|
+
mock_server_class.return_value = mock_server
|
|
117
|
+
mock_server.downloader.get_downloaded_models.return_value = ['distilbert-base-uncased']
|
|
118
|
+
mock_server.delete_model.return_value = True
|
|
119
|
+
|
|
120
|
+
result = self.runner.invoke(model, ['delete', 'distilbert-base-uncased', '--force'])
|
|
121
|
+
|
|
122
|
+
assert result.exit_code == 0
|
|
123
|
+
assert 'Successfully deleted' in result.output
|
|
124
|
+
mock_server.delete_model.assert_called_once_with('distilbert-base-uncased')
|
|
125
|
+
|
|
126
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
127
|
+
def test_delete_command_failure(self, mock_server_class):
|
|
128
|
+
"""Test delete command with failed deletion"""
|
|
129
|
+
mock_server = Mock()
|
|
130
|
+
mock_server_class.return_value = mock_server
|
|
131
|
+
mock_server.downloader.get_downloaded_models.return_value = ['distilbert-base-uncased']
|
|
132
|
+
mock_server.delete_model.return_value = False
|
|
133
|
+
|
|
134
|
+
result = self.runner.invoke(model, ['delete', 'distilbert-base-uncased', '--force'])
|
|
135
|
+
|
|
136
|
+
assert result.exit_code == 1
|
|
137
|
+
assert 'Failed to delete' in result.output
|
|
138
|
+
|
|
139
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
140
|
+
def test_delete_command_model_not_found(self, mock_server_class):
|
|
141
|
+
"""Test delete command with model not found"""
|
|
142
|
+
mock_server = Mock()
|
|
143
|
+
mock_server_class.return_value = mock_server
|
|
144
|
+
mock_server.downloader.get_downloaded_models.return_value = []
|
|
145
|
+
|
|
146
|
+
result = self.runner.invoke(model, ['delete', 'distilbert-base-uncased', '--force'])
|
|
147
|
+
|
|
148
|
+
assert result.exit_code == 1
|
|
149
|
+
assert 'not found' in result.output
|
|
150
|
+
|
|
151
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
152
|
+
def test_delete_command_with_confirmation(self, mock_server_class):
|
|
153
|
+
"""Test delete command with user confirmation"""
|
|
154
|
+
mock_server = Mock()
|
|
155
|
+
mock_server_class.return_value = mock_server
|
|
156
|
+
mock_server.downloader.get_downloaded_models.return_value = ['distilbert-base-uncased']
|
|
157
|
+
mock_server.delete_model.return_value = True
|
|
158
|
+
|
|
159
|
+
# Simulate user confirming deletion
|
|
160
|
+
result = self.runner.invoke(model, ['delete', 'distilbert-base-uncased'], input='y\n')
|
|
161
|
+
|
|
162
|
+
assert result.exit_code == 0
|
|
163
|
+
assert 'Successfully deleted' in result.output
|
|
164
|
+
|
|
165
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
166
|
+
def test_delete_command_cancelled(self, mock_server_class):
|
|
167
|
+
"""Test delete command when user cancels"""
|
|
168
|
+
mock_server = Mock()
|
|
169
|
+
mock_server_class.return_value = mock_server
|
|
170
|
+
mock_server.downloader.get_downloaded_models.return_value = ['distilbert-base-uncased']
|
|
171
|
+
|
|
172
|
+
# Simulate user cancelling deletion
|
|
173
|
+
result = self.runner.invoke(model, ['delete', 'distilbert-base-uncased'], input='n\n')
|
|
174
|
+
|
|
175
|
+
assert result.exit_code == 0
|
|
176
|
+
assert 'cancelled' in result.output
|
|
177
|
+
mock_server.delete_model.assert_not_called()
|
|
178
|
+
|
|
179
|
+
def test_stop_command_success(self):
|
|
180
|
+
"""Test stop command with successful stop"""
|
|
181
|
+
with patch('requests.get') as mock_get, \
|
|
182
|
+
patch('psutil.process_iter') as mock_proc_iter:
|
|
183
|
+
|
|
184
|
+
mock_response = Mock()
|
|
185
|
+
mock_response.status_code = 200
|
|
186
|
+
mock_get.return_value = mock_response
|
|
187
|
+
|
|
188
|
+
mock_proc = Mock()
|
|
189
|
+
mock_proc.pid = 1234
|
|
190
|
+
mock_proc.info = {'connections': [Mock(laddr=Mock(port=8080))]}
|
|
191
|
+
mock_proc_iter.return_value = [mock_proc]
|
|
192
|
+
|
|
193
|
+
result = self.runner.invoke(model, ['stop'])
|
|
194
|
+
|
|
195
|
+
assert result.exit_code == 0
|
|
196
|
+
assert 'Server stopped successfully' in result.output or 'Stopping server' in result.output
|
|
197
|
+
|
|
198
|
+
def test_stop_command_no_server(self):
|
|
199
|
+
"""Test stop command when no server is running"""
|
|
200
|
+
import requests
|
|
201
|
+
with patch('requests.get') as mock_get:
|
|
202
|
+
mock_get.side_effect = requests.exceptions.ConnectionError()
|
|
203
|
+
|
|
204
|
+
result = self.runner.invoke(model, ['stop'])
|
|
205
|
+
|
|
206
|
+
assert result.exit_code == 0
|
|
207
|
+
assert 'No server running' in result.output
|
|
208
|
+
|
|
209
|
+
def test_status_command_server_running(self):
|
|
210
|
+
"""Test status command when server is running"""
|
|
211
|
+
with patch('requests.get') as mock_get:
|
|
212
|
+
mock_health_response = Mock()
|
|
213
|
+
mock_health_response.status_code = 200
|
|
214
|
+
|
|
215
|
+
mock_models_response = Mock()
|
|
216
|
+
mock_models_response.status_code = 200
|
|
217
|
+
mock_models_response.json.return_value = {
|
|
218
|
+
'models': [
|
|
219
|
+
{'name': 'distilbert-base-uncased', 'parameters': '66M'}
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
mock_get.side_effect = [mock_health_response, mock_models_response]
|
|
224
|
+
|
|
225
|
+
result = self.runner.invoke(model, ['status'])
|
|
226
|
+
|
|
227
|
+
assert result.exit_code == 0
|
|
228
|
+
assert 'Server is running' in result.output
|
|
229
|
+
|
|
230
|
+
def test_status_command_server_not_running(self):
|
|
231
|
+
"""Test status command when server is not running"""
|
|
232
|
+
import requests
|
|
233
|
+
with patch('requests.get') as mock_get:
|
|
234
|
+
mock_get.side_effect = requests.exceptions.ConnectionError()
|
|
235
|
+
|
|
236
|
+
result = self.runner.invoke(model, ['status'])
|
|
237
|
+
|
|
238
|
+
assert result.exit_code == 0
|
|
239
|
+
assert 'No server running' in result.output
|
|
240
|
+
|
|
241
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
242
|
+
def test_recommend_command(self, mock_server_class):
|
|
243
|
+
"""Test recommend command"""
|
|
244
|
+
mock_server = Mock()
|
|
245
|
+
mock_server_class.return_value = mock_server
|
|
246
|
+
mock_server.recommend_model.return_value = "distilbert-base-uncased"
|
|
247
|
+
mock_server.get_system_info.return_value = {
|
|
248
|
+
'cpu_count': 4,
|
|
249
|
+
'memory_gb': 8.0,
|
|
250
|
+
'disk_free_gb': 100.0
|
|
251
|
+
}
|
|
252
|
+
mock_server.downloader.get_downloaded_models.return_value = []
|
|
253
|
+
|
|
254
|
+
result = self.runner.invoke(model, ['recommend'])
|
|
255
|
+
|
|
256
|
+
assert result.exit_code == 0
|
|
257
|
+
assert 'Recommended Model' in result.output
|
|
258
|
+
|
|
259
|
+
@patch('mcli.app.model_cmd.LightweightModelServer')
|
|
260
|
+
def test_start_command_with_auto_download(self, mock_server_class):
|
|
261
|
+
"""Test start command with auto-download"""
|
|
262
|
+
mock_server = Mock()
|
|
263
|
+
mock_server_class.return_value = mock_server
|
|
264
|
+
mock_server.recommend_model.return_value = "distilbert-base-uncased"
|
|
265
|
+
mock_server.downloader.get_downloaded_models.return_value = []
|
|
266
|
+
mock_server.download_and_load_model.return_value = True
|
|
267
|
+
|
|
268
|
+
# Use a timeout to avoid hanging on the infinite loop
|
|
269
|
+
import signal
|
|
270
|
+
|
|
271
|
+
def timeout_handler(signum, frame):
|
|
272
|
+
raise KeyboardInterrupt()
|
|
273
|
+
|
|
274
|
+
old_handler = signal.signal(signal.SIGALRM, timeout_handler)
|
|
275
|
+
signal.alarm(1)
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
result = self.runner.invoke(model, ['start', '--auto-download'])
|
|
279
|
+
# Command will be interrupted by KeyboardInterrupt
|
|
280
|
+
except KeyboardInterrupt:
|
|
281
|
+
pass
|
|
282
|
+
finally:
|
|
283
|
+
signal.alarm(0)
|
|
284
|
+
signal.signal(signal.SIGALRM, old_handler)
|
|
285
|
+
|
|
286
|
+
# Verify the model was downloaded
|
|
287
|
+
mock_server.download_and_load_model.assert_called()
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class TestModelCommandHelp:
|
|
291
|
+
"""Test suite for model command help text"""
|
|
292
|
+
|
|
293
|
+
def setup_method(self):
|
|
294
|
+
"""Setup test environment"""
|
|
295
|
+
self.runner = CliRunner()
|
|
296
|
+
|
|
297
|
+
def test_model_help(self):
|
|
298
|
+
"""Test model command help text"""
|
|
299
|
+
result = self.runner.invoke(model, ['--help'])
|
|
300
|
+
|
|
301
|
+
assert result.exit_code == 0
|
|
302
|
+
assert 'Model management commands' in result.output
|
|
303
|
+
|
|
304
|
+
def test_list_help(self):
|
|
305
|
+
"""Test list command help text"""
|
|
306
|
+
result = self.runner.invoke(model, ['list', '--help'])
|
|
307
|
+
|
|
308
|
+
assert result.exit_code == 0
|
|
309
|
+
assert 'List available and downloaded models' in result.output
|
|
310
|
+
|
|
311
|
+
def test_download_help(self):
|
|
312
|
+
"""Test download command help text"""
|
|
313
|
+
result = self.runner.invoke(model, ['download', '--help'])
|
|
314
|
+
|
|
315
|
+
assert result.exit_code == 0
|
|
316
|
+
assert 'Download a specific lightweight model' in result.output
|
|
317
|
+
|
|
318
|
+
def test_pull_help(self):
|
|
319
|
+
"""Test pull command help text"""
|
|
320
|
+
result = self.runner.invoke(model, ['pull', '--help'])
|
|
321
|
+
|
|
322
|
+
assert result.exit_code == 0
|
|
323
|
+
assert 'Pull' in result.output or 'download' in result.output
|
|
324
|
+
|
|
325
|
+
def test_delete_help(self):
|
|
326
|
+
"""Test delete command help text"""
|
|
327
|
+
result = self.runner.invoke(model, ['delete', '--help'])
|
|
328
|
+
|
|
329
|
+
assert result.exit_code == 0
|
|
330
|
+
assert 'Delete a downloaded lightweight model' in result.output
|
|
331
|
+
|
|
332
|
+
def test_stop_help(self):
|
|
333
|
+
"""Test stop command help text"""
|
|
334
|
+
result = self.runner.invoke(model, ['stop', '--help'])
|
|
335
|
+
|
|
336
|
+
assert result.exit_code == 0
|
|
337
|
+
assert 'Stop the lightweight model server' in result.output
|
|
338
|
+
|
|
339
|
+
def test_start_help(self):
|
|
340
|
+
"""Test start command help text"""
|
|
341
|
+
result = self.runner.invoke(model, ['start', '--help'])
|
|
342
|
+
|
|
343
|
+
assert result.exit_code == 0
|
|
344
|
+
assert 'Start the lightweight model server' in result.output
|
|
345
|
+
|
|
346
|
+
def test_status_help(self):
|
|
347
|
+
"""Test status command help text"""
|
|
348
|
+
result = self.runner.invoke(model, ['status', '--help'])
|
|
349
|
+
|
|
350
|
+
assert result.exit_code == 0
|
|
351
|
+
assert 'Check status of the lightweight model server' in result.output
|
|
352
|
+
|
|
353
|
+
def test_recommend_help(self):
|
|
354
|
+
"""Test recommend command help text"""
|
|
355
|
+
result = self.runner.invoke(model, ['recommend', '--help'])
|
|
356
|
+
|
|
357
|
+
assert result.exit_code == 0
|
|
358
|
+
assert 'Get model recommendation' in result.output
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
if __name__ == '__main__':
|
|
362
|
+
pytest.main([__file__, '-v'])
|