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.

Files changed (56) hide show
  1. mcli/app/commands_cmd.py +51 -39
  2. mcli/app/completion_helpers.py +4 -13
  3. mcli/app/main.py +21 -25
  4. mcli/app/model_cmd.py +119 -9
  5. mcli/lib/custom_commands.py +16 -11
  6. mcli/ml/api/app.py +1 -5
  7. mcli/ml/dashboard/app.py +2 -2
  8. mcli/ml/dashboard/app_integrated.py +168 -116
  9. mcli/ml/dashboard/app_supabase.py +7 -3
  10. mcli/ml/dashboard/app_training.py +3 -6
  11. mcli/ml/dashboard/components/charts.py +74 -115
  12. mcli/ml/dashboard/components/metrics.py +24 -44
  13. mcli/ml/dashboard/components/tables.py +32 -40
  14. mcli/ml/dashboard/overview.py +102 -78
  15. mcli/ml/dashboard/pages/cicd.py +103 -56
  16. mcli/ml/dashboard/pages/debug_dependencies.py +35 -28
  17. mcli/ml/dashboard/pages/gravity_viz.py +374 -313
  18. mcli/ml/dashboard/pages/monte_carlo_predictions.py +50 -48
  19. mcli/ml/dashboard/pages/predictions_enhanced.py +396 -248
  20. mcli/ml/dashboard/pages/scrapers_and_logs.py +299 -273
  21. mcli/ml/dashboard/pages/test_portfolio.py +153 -121
  22. mcli/ml/dashboard/pages/trading.py +238 -169
  23. mcli/ml/dashboard/pages/workflows.py +129 -84
  24. mcli/ml/dashboard/streamlit_extras_utils.py +70 -79
  25. mcli/ml/dashboard/utils.py +24 -21
  26. mcli/ml/dashboard/warning_suppression.py +6 -4
  27. mcli/ml/database/session.py +16 -5
  28. mcli/ml/mlops/pipeline_orchestrator.py +1 -3
  29. mcli/ml/predictions/monte_carlo.py +6 -18
  30. mcli/ml/trading/alpaca_client.py +95 -96
  31. mcli/ml/trading/migrations.py +76 -40
  32. mcli/ml/trading/models.py +78 -60
  33. mcli/ml/trading/paper_trading.py +92 -74
  34. mcli/ml/trading/risk_management.py +106 -85
  35. mcli/ml/trading/trading_service.py +155 -110
  36. mcli/ml/training/train_model.py +1 -3
  37. mcli/{app → self}/completion_cmd.py +6 -6
  38. mcli/self/self_cmd.py +100 -57
  39. mcli/test/test_cmd.py +30 -0
  40. mcli/workflow/daemon/daemon.py +2 -0
  41. mcli/workflow/model_service/openai_adapter.py +347 -0
  42. mcli/workflow/politician_trading/models.py +6 -2
  43. mcli/workflow/politician_trading/scrapers_corporate_registry.py +39 -88
  44. mcli/workflow/politician_trading/scrapers_free_sources.py +32 -39
  45. mcli/workflow/politician_trading/scrapers_third_party.py +21 -39
  46. mcli/workflow/politician_trading/seed_database.py +70 -89
  47. {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/METADATA +1 -1
  48. {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/RECORD +56 -54
  49. /mcli/{app → self}/logs_cmd.py +0 -0
  50. /mcli/{app → self}/redis_cmd.py +0 -0
  51. /mcli/{app → self}/visual_cmd.py +0 -0
  52. /mcli/{app → test}/cron_test_cmd.py +0 -0
  53. {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/WHEEL +0 -0
  54. {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/entry_points.txt +0 -0
  55. {mcli_framework-7.5.1.dist-info → mcli_framework-7.6.1.dist-info}/licenses/LICENSE +0 -0
  56. {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("ignore", message=".*Session state does not function.*")
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("streamlit.runtime.scriptrunner_utils.script_run_context").setLevel(logging.CRITICAL)
369
- logging.getLogger("streamlit.runtime.caching.cache_data_api").setLevel(logging.CRITICAL)
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(command_name: str, command_group: str, description: str) -> Optional[str]:
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('EDITOR')
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 ['vim', 'nano', 'code', 'subl', 'atom', 'emacs']:
443
- if subprocess.run(['which', common_editor], capture_output=True).returncode == 0:
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("❌ No editor found. Please set the EDITOR environment variable or install vim/nano.")
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='w', suffix='.py', delete=False) as temp_file:
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("❌ Editor requires an interactive terminal. Use --template flag for non-interactive mode.")
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, 'r') as f:
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('\n')
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('# Your command implementation goes here:'):
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 = '\n'.join(code_lines).strip()
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["code"] = f'''"""
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["code"] = f'''"""
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, '<string>', 'exec')
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['code'] = new_code
1247
- command_data['updated_at'] = datetime.now().isoformat()
1256
+ command_data["code"] = new_code
1257
+ command_data["updated_at"] = datetime.now().isoformat()
1248
1258
 
1249
- with open(command_file, 'w') as f:
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()
@@ -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