mcli-framework 7.5.1__py3-none-any.whl → 7.6.1__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/commands_cmd.py +51 -39
- mcli/app/completion_helpers.py +4 -13
- mcli/app/main.py +21 -25
- mcli/app/model_cmd.py +119 -9
- mcli/lib/custom_commands.py +16 -11
- mcli/ml/api/app.py +1 -5
- mcli/ml/dashboard/app.py +2 -2
- mcli/ml/dashboard/app_integrated.py +168 -116
- mcli/ml/dashboard/app_supabase.py +7 -3
- mcli/ml/dashboard/app_training.py +3 -6
- mcli/ml/dashboard/components/charts.py +74 -115
- mcli/ml/dashboard/components/metrics.py +24 -44
- mcli/ml/dashboard/components/tables.py +32 -40
- mcli/ml/dashboard/overview.py +102 -78
- mcli/ml/dashboard/pages/cicd.py +103 -56
- mcli/ml/dashboard/pages/debug_dependencies.py +35 -28
- mcli/ml/dashboard/pages/gravity_viz.py +374 -313
- mcli/ml/dashboard/pages/monte_carlo_predictions.py +50 -48
- mcli/ml/dashboard/pages/predictions_enhanced.py +396 -248
- mcli/ml/dashboard/pages/scrapers_and_logs.py +299 -273
- mcli/ml/dashboard/pages/test_portfolio.py +153 -121
- mcli/ml/dashboard/pages/trading.py +238 -169
- mcli/ml/dashboard/pages/workflows.py +129 -84
- mcli/ml/dashboard/streamlit_extras_utils.py +70 -79
- mcli/ml/dashboard/utils.py +24 -21
- mcli/ml/dashboard/warning_suppression.py +6 -4
- mcli/ml/database/session.py +16 -5
- mcli/ml/mlops/pipeline_orchestrator.py +1 -3
- mcli/ml/predictions/monte_carlo.py +6 -18
- mcli/ml/trading/alpaca_client.py +95 -96
- mcli/ml/trading/migrations.py +76 -40
- mcli/ml/trading/models.py +78 -60
- mcli/ml/trading/paper_trading.py +92 -74
- mcli/ml/trading/risk_management.py +106 -85
- mcli/ml/trading/trading_service.py +155 -110
- mcli/ml/training/train_model.py +1 -3
- mcli/{app → self}/completion_cmd.py +6 -6
- mcli/self/self_cmd.py +100 -57
- mcli/test/test_cmd.py +30 -0
- mcli/workflow/daemon/daemon.py +2 -0
- mcli/workflow/model_service/openai_adapter.py +347 -0
- mcli/workflow/politician_trading/models.py +6 -2
- mcli/workflow/politician_trading/scrapers_corporate_registry.py +39 -88
- mcli/workflow/politician_trading/scrapers_free_sources.py +32 -39
- mcli/workflow/politician_trading/scrapers_third_party.py +21 -39
- mcli/workflow/politician_trading/seed_database.py +70 -89
- {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/METADATA +1 -1
- {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/RECORD +56 -54
- /mcli/{app → self}/logs_cmd.py +0 -0
- /mcli/{app → self}/redis_cmd.py +0 -0
- /mcli/{app → self}/visual_cmd.py +0 -0
- /mcli/{app → test}/cron_test_cmd.py +0 -0
- {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/WHEEL +0 -0
- {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/entry_points.txt +0 -0
- {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/licenses/LICENSE +0 -0
- {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/top_level.txt +0 -0
mcli/self/self_cmd.py
CHANGED
|
@@ -29,8 +29,8 @@ try:
|
|
|
29
29
|
except ImportError:
|
|
30
30
|
process = None
|
|
31
31
|
|
|
32
|
-
from mcli.lib.logger.logger import get_logger
|
|
33
32
|
from mcli.lib.custom_commands import get_command_manager
|
|
33
|
+
from mcli.lib.logger.logger import get_logger
|
|
34
34
|
|
|
35
35
|
logger = get_logger()
|
|
36
36
|
|
|
@@ -345,29 +345,35 @@ def collect_commands() -> List[Dict[str, Any]]:
|
|
|
345
345
|
|
|
346
346
|
try:
|
|
347
347
|
# Suppress Streamlit warnings and logging during module import
|
|
348
|
-
import warnings
|
|
349
348
|
import logging
|
|
350
|
-
import sys
|
|
351
349
|
import os
|
|
350
|
+
import sys
|
|
351
|
+
import warnings
|
|
352
352
|
from contextlib import redirect_stderr
|
|
353
353
|
from io import StringIO
|
|
354
|
-
|
|
354
|
+
|
|
355
355
|
# Suppress Python warnings
|
|
356
356
|
with warnings.catch_warnings():
|
|
357
357
|
warnings.filterwarnings("ignore", message=".*missing ScriptRunContext.*")
|
|
358
358
|
warnings.filterwarnings("ignore", message=".*No runtime found.*")
|
|
359
|
-
warnings.filterwarnings(
|
|
359
|
+
warnings.filterwarnings(
|
|
360
|
+
"ignore", message=".*Session state does not function.*"
|
|
361
|
+
)
|
|
360
362
|
warnings.filterwarnings("ignore", message=".*to view this Streamlit app.*")
|
|
361
|
-
|
|
363
|
+
|
|
362
364
|
# Suppress Streamlit logger warnings
|
|
363
365
|
streamlit_logger = logging.getLogger("streamlit")
|
|
364
366
|
original_level = streamlit_logger.level
|
|
365
367
|
streamlit_logger.setLevel(logging.CRITICAL)
|
|
366
|
-
|
|
368
|
+
|
|
367
369
|
# Also suppress specific Streamlit sub-loggers
|
|
368
|
-
logging.getLogger(
|
|
369
|
-
|
|
370
|
-
|
|
370
|
+
logging.getLogger(
|
|
371
|
+
"streamlit.runtime.scriptrunner_utils.script_run_context"
|
|
372
|
+
).setLevel(logging.CRITICAL)
|
|
373
|
+
logging.getLogger("streamlit.runtime.caching.cache_data_api").setLevel(
|
|
374
|
+
logging.CRITICAL
|
|
375
|
+
)
|
|
376
|
+
|
|
371
377
|
# Redirect stderr to suppress Streamlit warnings
|
|
372
378
|
with redirect_stderr(StringIO()):
|
|
373
379
|
try:
|
|
@@ -417,40 +423,44 @@ def collect_commands() -> List[Dict[str, Any]]:
|
|
|
417
423
|
return commands
|
|
418
424
|
|
|
419
425
|
|
|
420
|
-
def open_editor_for_command(
|
|
426
|
+
def open_editor_for_command(
|
|
427
|
+
command_name: str, command_group: str, description: str
|
|
428
|
+
) -> Optional[str]:
|
|
421
429
|
"""
|
|
422
430
|
Open the user's default editor to allow them to write command logic.
|
|
423
|
-
|
|
431
|
+
|
|
424
432
|
Args:
|
|
425
433
|
command_name: Name of the command
|
|
426
434
|
command_group: Group for the command
|
|
427
435
|
description: Description of the command
|
|
428
|
-
|
|
436
|
+
|
|
429
437
|
Returns:
|
|
430
438
|
The Python code written by the user, or None if cancelled
|
|
431
439
|
"""
|
|
432
|
-
import tempfile
|
|
433
|
-
import subprocess
|
|
434
440
|
import os
|
|
441
|
+
import subprocess
|
|
435
442
|
import sys
|
|
443
|
+
import tempfile
|
|
436
444
|
from pathlib import Path
|
|
437
|
-
|
|
445
|
+
|
|
438
446
|
# Get the user's default editor
|
|
439
|
-
editor = os.environ.get(
|
|
447
|
+
editor = os.environ.get("EDITOR")
|
|
440
448
|
if not editor:
|
|
441
449
|
# Try common editors in order of preference
|
|
442
|
-
for common_editor in [
|
|
443
|
-
if subprocess.run([
|
|
450
|
+
for common_editor in ["vim", "nano", "code", "subl", "atom", "emacs"]:
|
|
451
|
+
if subprocess.run(["which", common_editor], capture_output=True).returncode == 0:
|
|
444
452
|
editor = common_editor
|
|
445
453
|
break
|
|
446
|
-
|
|
454
|
+
|
|
447
455
|
if not editor:
|
|
448
|
-
click.echo(
|
|
456
|
+
click.echo(
|
|
457
|
+
"❌ No editor found. Please set the EDITOR environment variable or install vim/nano."
|
|
458
|
+
)
|
|
449
459
|
return None
|
|
450
|
-
|
|
460
|
+
|
|
451
461
|
# Create a temporary file with the template
|
|
452
462
|
template = get_command_template(command_name, command_group)
|
|
453
|
-
|
|
463
|
+
|
|
454
464
|
# Add helpful comments to the template
|
|
455
465
|
enhanced_template = f'''"""
|
|
456
466
|
{command_name} command for mcli.{command_group}.
|
|
@@ -491,64 +501,66 @@ logger = get_logger()
|
|
|
491
501
|
# logger.info(f"Executing {command_name} command with name: {{name}}")
|
|
492
502
|
# click.echo(f"Hello, {{name}}! This is the {command_name} command.")
|
|
493
503
|
'''
|
|
494
|
-
|
|
504
|
+
|
|
495
505
|
# Create temporary file
|
|
496
|
-
with tempfile.NamedTemporaryFile(mode=
|
|
506
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as temp_file:
|
|
497
507
|
temp_file.write(enhanced_template)
|
|
498
508
|
temp_file_path = temp_file.name
|
|
499
|
-
|
|
509
|
+
|
|
500
510
|
try:
|
|
501
511
|
# Check if we're in an interactive environment
|
|
502
512
|
if not sys.stdin.isatty() or not sys.stdout.isatty():
|
|
503
|
-
click.echo(
|
|
513
|
+
click.echo(
|
|
514
|
+
"❌ Editor requires an interactive terminal. Use --template flag for non-interactive mode."
|
|
515
|
+
)
|
|
504
516
|
return None
|
|
505
|
-
|
|
517
|
+
|
|
506
518
|
# Open editor
|
|
507
519
|
click.echo(f"📝 Opening {editor} to edit command logic...")
|
|
508
520
|
click.echo("💡 Write your Python command logic and save the file to continue.")
|
|
509
521
|
click.echo("💡 Press Ctrl+C to cancel command creation.")
|
|
510
|
-
|
|
522
|
+
|
|
511
523
|
# Run the editor
|
|
512
524
|
result = subprocess.run([editor, temp_file_path], check=False)
|
|
513
|
-
|
|
525
|
+
|
|
514
526
|
if result.returncode != 0:
|
|
515
527
|
click.echo("❌ Editor exited with error. Command creation cancelled.")
|
|
516
528
|
return None
|
|
517
|
-
|
|
529
|
+
|
|
518
530
|
# Read the edited content
|
|
519
|
-
with open(temp_file_path,
|
|
531
|
+
with open(temp_file_path, "r") as f:
|
|
520
532
|
edited_code = f.read()
|
|
521
|
-
|
|
533
|
+
|
|
522
534
|
# Check if the file was actually edited (not just the template)
|
|
523
535
|
if edited_code.strip() == enhanced_template.strip():
|
|
524
536
|
click.echo("⚠️ No changes detected. Command creation cancelled.")
|
|
525
537
|
return None
|
|
526
|
-
|
|
538
|
+
|
|
527
539
|
# Extract the actual command code (remove the instructions)
|
|
528
|
-
lines = edited_code.split(
|
|
540
|
+
lines = edited_code.split("\n")
|
|
529
541
|
code_lines = []
|
|
530
542
|
in_code_section = False
|
|
531
|
-
|
|
543
|
+
|
|
532
544
|
for line in lines:
|
|
533
|
-
if line.strip().startswith(
|
|
545
|
+
if line.strip().startswith("# Your command implementation goes here:"):
|
|
534
546
|
in_code_section = True
|
|
535
547
|
continue
|
|
536
548
|
if in_code_section:
|
|
537
549
|
code_lines.append(line)
|
|
538
|
-
|
|
550
|
+
|
|
539
551
|
if not code_lines or not any(line.strip() for line in code_lines):
|
|
540
552
|
# Fallback: use the entire file content
|
|
541
553
|
code_lines = lines
|
|
542
|
-
|
|
543
|
-
final_code =
|
|
544
|
-
|
|
554
|
+
|
|
555
|
+
final_code = "\n".join(code_lines).strip()
|
|
556
|
+
|
|
545
557
|
if not final_code:
|
|
546
558
|
click.echo("❌ No command code found. Command creation cancelled.")
|
|
547
559
|
return None
|
|
548
|
-
|
|
560
|
+
|
|
549
561
|
click.echo("✅ Command code captured successfully!")
|
|
550
562
|
return final_code
|
|
551
|
-
|
|
563
|
+
|
|
552
564
|
except KeyboardInterrupt:
|
|
553
565
|
click.echo("\n❌ Command creation cancelled by user.")
|
|
554
566
|
return None
|
|
@@ -611,7 +623,9 @@ def extract_workflow_commands(output):
|
|
|
611
623
|
|
|
612
624
|
if isinstance(cmd_obj, click.Group):
|
|
613
625
|
# For groups, create a template
|
|
614
|
-
command_info[
|
|
626
|
+
command_info[
|
|
627
|
+
"code"
|
|
628
|
+
] = f'''"""
|
|
615
629
|
{cmd_name} workflow command.
|
|
616
630
|
"""
|
|
617
631
|
import click
|
|
@@ -625,7 +639,9 @@ def app():
|
|
|
625
639
|
'''
|
|
626
640
|
else:
|
|
627
641
|
# For regular commands, create a template
|
|
628
|
-
command_info[
|
|
642
|
+
command_info[
|
|
643
|
+
"code"
|
|
644
|
+
] = f'''"""
|
|
629
645
|
{cmd_name} workflow command.
|
|
630
646
|
"""
|
|
631
647
|
import click
|
|
@@ -650,9 +666,7 @@ def app():
|
|
|
650
666
|
click.echo(
|
|
651
667
|
f"\n💡 These are templates. Import with: mcli self import-commands {output_file}"
|
|
652
668
|
)
|
|
653
|
-
click.echo(
|
|
654
|
-
" Then customize the code in ~/.mcli/commands/<command>.json"
|
|
655
|
-
)
|
|
669
|
+
click.echo(" Then customize the code in ~/.mcli/commands/<command>.json")
|
|
656
670
|
return 0
|
|
657
671
|
else:
|
|
658
672
|
click.echo("⚠️ No workflow commands found to extract")
|
|
@@ -1229,24 +1243,20 @@ def update(check: bool, pre: bool, yes: bool, skip_ci_check: bool):
|
|
|
1229
1243
|
|
|
1230
1244
|
console.print(f"[dim]{traceback.format_exc()}[/dim]")
|
|
1231
1245
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
1246
|
# Validate syntax
|
|
1235
1247
|
try:
|
|
1236
|
-
compile(new_code,
|
|
1248
|
+
compile(new_code, "<string>", "exec")
|
|
1237
1249
|
except SyntaxError as e:
|
|
1238
1250
|
click.echo(f"❌ Syntax error in edited code: {e}", err=True)
|
|
1239
|
-
should_save = Prompt.ask(
|
|
1240
|
-
"Save anyway?", choices=["y", "n"], default="n"
|
|
1241
|
-
)
|
|
1251
|
+
should_save = Prompt.ask("Save anyway?", choices=["y", "n"], default="n")
|
|
1242
1252
|
if should_save.lower() != "y":
|
|
1243
1253
|
return 1
|
|
1244
1254
|
|
|
1245
1255
|
# Update the command
|
|
1246
|
-
command_data[
|
|
1247
|
-
command_data[
|
|
1256
|
+
command_data["code"] = new_code
|
|
1257
|
+
command_data["updated_at"] = datetime.now().isoformat()
|
|
1248
1258
|
|
|
1249
|
-
with open(command_file,
|
|
1259
|
+
with open(command_file, "w") as f:
|
|
1250
1260
|
json.dump(command_data, f, indent=2)
|
|
1251
1261
|
|
|
1252
1262
|
# Update lockfile
|
|
@@ -1265,6 +1275,39 @@ def update(check: bool, pre: bool, yes: bool, skip_ci_check: bool):
|
|
|
1265
1275
|
# Register the plugin group with self_app
|
|
1266
1276
|
self_app.add_command(plugin)
|
|
1267
1277
|
|
|
1278
|
+
# Import and register new commands that have been moved to self
|
|
1279
|
+
try:
|
|
1280
|
+
from mcli.self.completion_cmd import completion
|
|
1281
|
+
|
|
1282
|
+
self_app.add_command(completion, name="completion")
|
|
1283
|
+
logger.debug("Added completion command to self group")
|
|
1284
|
+
except ImportError as e:
|
|
1285
|
+
logger.debug(f"Could not load completion command: {e}")
|
|
1286
|
+
|
|
1287
|
+
try:
|
|
1288
|
+
from mcli.self.logs_cmd import logs_group
|
|
1289
|
+
|
|
1290
|
+
self_app.add_command(logs_group, name="logs")
|
|
1291
|
+
logger.debug("Added logs command to self group")
|
|
1292
|
+
except ImportError as e:
|
|
1293
|
+
logger.debug(f"Could not load logs command: {e}")
|
|
1294
|
+
|
|
1295
|
+
try:
|
|
1296
|
+
from mcli.self.redis_cmd import redis_group
|
|
1297
|
+
|
|
1298
|
+
self_app.add_command(redis_group, name="redis")
|
|
1299
|
+
logger.debug("Added redis command to self group")
|
|
1300
|
+
except ImportError as e:
|
|
1301
|
+
logger.debug(f"Could not load redis command: {e}")
|
|
1302
|
+
|
|
1303
|
+
try:
|
|
1304
|
+
from mcli.self.visual_cmd import visual
|
|
1305
|
+
|
|
1306
|
+
self_app.add_command(visual, name="visual")
|
|
1307
|
+
logger.debug("Added visual command to self group")
|
|
1308
|
+
except ImportError as e:
|
|
1309
|
+
logger.debug(f"Could not load visual command: {e}")
|
|
1310
|
+
|
|
1268
1311
|
# This part is important to make the command available to the CLI
|
|
1269
1312
|
if __name__ == "__main__":
|
|
1270
1313
|
self_app()
|
mcli/test/test_cmd.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test command group for mcli.
|
|
3
|
+
Contains testing and validation utilities.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from mcli.lib.logger.logger import get_logger
|
|
9
|
+
|
|
10
|
+
logger = get_logger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group(name="test")
|
|
14
|
+
def test_group():
|
|
15
|
+
"""Testing and validation commands"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Import and register subcommands
|
|
20
|
+
try:
|
|
21
|
+
from mcli.test.cron_test_cmd import cron_test
|
|
22
|
+
|
|
23
|
+
test_group.add_command(cron_test, name="cron")
|
|
24
|
+
logger.debug("Added cron test command to test group")
|
|
25
|
+
except ImportError as e:
|
|
26
|
+
logger.debug(f"Could not load cron test command: {e}")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
test_group()
|
mcli/workflow/daemon/daemon.py
CHANGED
|
@@ -20,6 +20,7 @@ from sklearn.metrics.pairwise import cosine_similarity
|
|
|
20
20
|
try:
|
|
21
21
|
from watchdog.events import FileSystemEventHandler
|
|
22
22
|
from watchdog.observers import Observer
|
|
23
|
+
|
|
23
24
|
HAS_WATCHDOG = True
|
|
24
25
|
except ImportError:
|
|
25
26
|
# Watchdog not available, file watching will be disabled
|
|
@@ -40,6 +41,7 @@ class CommandDatabase:
|
|
|
40
41
|
"""Stub database for backward compatibility.
|
|
41
42
|
Commands are now stored as JSON files and loaded via the custom commands system.
|
|
42
43
|
"""
|
|
44
|
+
|
|
43
45
|
def __init__(self, db_path: Optional[str] = None):
|
|
44
46
|
logger.debug("CommandDatabase stub initialized - commands now managed via JSON files")
|
|
45
47
|
pass
|