mcli-framework 7.10.0__py3-none-any.whl → 7.10.2__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 (42) hide show
  1. mcli/lib/custom_commands.py +10 -0
  2. mcli/lib/optional_deps.py +240 -0
  3. mcli/ml/backtesting/run.py +5 -3
  4. mcli/ml/models/ensemble_models.py +1 -0
  5. mcli/ml/models/recommendation_models.py +1 -0
  6. mcli/ml/optimization/optimize.py +6 -4
  7. mcli/ml/serving/serve.py +2 -2
  8. mcli/ml/training/train.py +14 -7
  9. mcli/self/completion_cmd.py +2 -2
  10. mcli/workflow/doc_convert.py +82 -112
  11. mcli/workflow/git_commit/ai_service.py +13 -2
  12. mcli/workflow/notebook/converter.py +375 -0
  13. mcli/workflow/notebook/notebook_cmd.py +441 -0
  14. mcli/workflow/notebook/schema.py +402 -0
  15. mcli/workflow/notebook/validator.py +313 -0
  16. mcli/workflow/workflow.py +14 -0
  17. {mcli_framework-7.10.0.dist-info → mcli_framework-7.10.2.dist-info}/METADATA +37 -3
  18. {mcli_framework-7.10.0.dist-info → mcli_framework-7.10.2.dist-info}/RECORD +22 -37
  19. mcli/ml/features/political_features.py +0 -677
  20. mcli/ml/preprocessing/politician_trading_preprocessor.py +0 -570
  21. mcli/workflow/politician_trading/config.py +0 -134
  22. mcli/workflow/politician_trading/connectivity.py +0 -492
  23. mcli/workflow/politician_trading/data_sources.py +0 -654
  24. mcli/workflow/politician_trading/database.py +0 -412
  25. mcli/workflow/politician_trading/demo.py +0 -249
  26. mcli/workflow/politician_trading/models.py +0 -327
  27. mcli/workflow/politician_trading/monitoring.py +0 -413
  28. mcli/workflow/politician_trading/scrapers.py +0 -1074
  29. mcli/workflow/politician_trading/scrapers_california.py +0 -434
  30. mcli/workflow/politician_trading/scrapers_corporate_registry.py +0 -797
  31. mcli/workflow/politician_trading/scrapers_eu.py +0 -376
  32. mcli/workflow/politician_trading/scrapers_free_sources.py +0 -509
  33. mcli/workflow/politician_trading/scrapers_third_party.py +0 -373
  34. mcli/workflow/politician_trading/scrapers_uk.py +0 -378
  35. mcli/workflow/politician_trading/scrapers_us_states.py +0 -471
  36. mcli/workflow/politician_trading/seed_database.py +0 -520
  37. mcli/workflow/politician_trading/supabase_functions.py +0 -354
  38. mcli/workflow/politician_trading/workflow.py +0 -879
  39. {mcli_framework-7.10.0.dist-info → mcli_framework-7.10.2.dist-info}/WHEEL +0 -0
  40. {mcli_framework-7.10.0.dist-info → mcli_framework-7.10.2.dist-info}/entry_points.txt +0 -0
  41. {mcli_framework-7.10.0.dist-info → mcli_framework-7.10.2.dist-info}/licenses/LICENSE +0 -0
  42. {mcli_framework-7.10.0.dist-info → mcli_framework-7.10.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,441 @@
1
+ """
2
+ CLI commands for MCLI workflow notebook management.
3
+
4
+ Provides commands for:
5
+ - Converting between workflow and notebook formats
6
+ - Migrating existing workflows
7
+ - Validating notebooks
8
+ - Launching the visual editor
9
+ """
10
+
11
+ import json
12
+ from pathlib import Path
13
+ from typing import Optional
14
+
15
+ import click
16
+
17
+ from mcli.lib.logger.logger import get_logger
18
+ from mcli.lib.paths import get_custom_commands_dir
19
+ from mcli.lib.ui.styling import error, info, success, warning
20
+
21
+ from .converter import WorkflowConverter
22
+ from .schema import WorkflowNotebook
23
+ from .validator import NotebookValidator
24
+
25
+ logger = get_logger()
26
+
27
+
28
+ @click.group(name="notebook")
29
+ def notebook():
30
+ """Workflow notebook management commands"""
31
+ pass
32
+
33
+
34
+ @notebook.command(name="convert")
35
+ @click.argument("input_file", type=click.Path(exists=True))
36
+ @click.option(
37
+ "--to",
38
+ "format_type",
39
+ type=click.Choice(["notebook", "workflow"]),
40
+ required=True,
41
+ help="Target format",
42
+ )
43
+ @click.option(
44
+ "-o",
45
+ "--output",
46
+ type=click.Path(),
47
+ help="Output file path (defaults to input file)",
48
+ )
49
+ @click.option(
50
+ "--backup/--no-backup",
51
+ default=True,
52
+ help="Create backup before conversion",
53
+ )
54
+ def convert(input_file: str, format_type: str, output: Optional[str], backup: bool):
55
+ """
56
+ Convert between workflow and notebook formats.
57
+
58
+ Examples:
59
+
60
+ # Convert workflow to notebook
61
+ mcli workflow notebook convert workflow.json --to notebook
62
+
63
+ # Convert notebook to workflow
64
+ mcli workflow notebook convert notebook.json --to workflow -o output.json
65
+ """
66
+ input_path = Path(input_file)
67
+ output_path = Path(output) if output else input_path
68
+
69
+ # Create backup if requested
70
+ if backup and output_path == input_path:
71
+ backup_path = input_path.with_suffix(".json.bak")
72
+ import shutil
73
+
74
+ shutil.copy2(input_path, backup_path)
75
+ info(f"Created backup: {backup_path}")
76
+
77
+ try:
78
+ if format_type == "notebook":
79
+ # Convert to notebook format
80
+ result_path = WorkflowConverter.convert_file_to_notebook(input_path, output_path)
81
+ success(f"Converted to notebook format: {result_path}")
82
+ else:
83
+ # Convert to workflow format
84
+ result_path = WorkflowConverter.convert_file_to_workflow(input_path, output_path)
85
+ success(f"Converted to workflow format: {result_path}")
86
+
87
+ except Exception as e:
88
+ error(f"Conversion failed: {e}")
89
+ raise click.Abort()
90
+
91
+
92
+ @notebook.command(name="migrate")
93
+ @click.option(
94
+ "-d",
95
+ "--directory",
96
+ type=click.Path(exists=True, file_okay=False),
97
+ default=None,
98
+ help="Directory to migrate (defaults to ~/.mcli/commands)",
99
+ )
100
+ @click.option(
101
+ "--backup/--no-backup",
102
+ default=True,
103
+ help="Create backup files before migration",
104
+ )
105
+ @click.option(
106
+ "--in-place/--separate",
107
+ default=True,
108
+ help="Convert in place or create separate files",
109
+ )
110
+ @click.option(
111
+ "--dry-run",
112
+ is_flag=True,
113
+ help="Show what would be migrated without making changes",
114
+ )
115
+ def migrate(directory: Optional[str], backup: bool, in_place: bool, dry_run: bool):
116
+ """
117
+ Migrate all workflow files in a directory to notebook format.
118
+
119
+ Examples:
120
+
121
+ # Migrate all workflows in default directory
122
+ mcli workflow notebook migrate
123
+
124
+ # Dry run to see what would be migrated
125
+ mcli workflow notebook migrate --dry-run
126
+
127
+ # Migrate specific directory without backup
128
+ mcli workflow notebook migrate -d /path/to/workflows --no-backup
129
+ """
130
+ target_dir = Path(directory) if directory else get_custom_commands_dir()
131
+
132
+ info(f"Migrating workflows in: {target_dir}")
133
+
134
+ if dry_run:
135
+ warning("DRY RUN MODE - No files will be modified")
136
+ # Count files that would be migrated
137
+ count = 0
138
+ for json_file in target_dir.glob("*.json"):
139
+ if json_file.name == "commands.lock.json":
140
+ continue
141
+ try:
142
+ with open(json_file, "r") as f:
143
+ data = json.load(f)
144
+ if "nbformat" not in data:
145
+ count += 1
146
+ info(f" Would convert: {json_file.name}")
147
+ except Exception as e:
148
+ warning(f" Would skip {json_file.name}: {e}")
149
+
150
+ info(f"\nTotal files to migrate: {count}")
151
+ return
152
+
153
+ try:
154
+ results = WorkflowConverter.migrate_directory(target_dir, backup=backup, in_place=in_place)
155
+
156
+ success(f"\nMigration complete:")
157
+ info(f" Total files: {results['total']}")
158
+ success(f" Converted: {results['converted']}")
159
+ warning(f" Skipped: {results['skipped']}")
160
+ if results["failed"] > 0:
161
+ error(f" Failed: {results['failed']}")
162
+
163
+ if results["files"]:
164
+ info("\nConverted files:")
165
+ for file_path in results["files"]:
166
+ info(f" - {Path(file_path).name}")
167
+
168
+ except Exception as e:
169
+ error(f"Migration failed: {e}")
170
+ raise click.Abort()
171
+
172
+
173
+ @notebook.command(name="validate")
174
+ @click.argument("notebook_file", type=click.Path(exists=True))
175
+ @click.option(
176
+ "--schema",
177
+ is_flag=True,
178
+ help="Validate against JSON schema",
179
+ )
180
+ @click.option(
181
+ "--syntax",
182
+ is_flag=True,
183
+ help="Validate code syntax",
184
+ )
185
+ @click.option(
186
+ "--all",
187
+ "validate_all",
188
+ is_flag=True,
189
+ help="Run all validations",
190
+ )
191
+ def validate(notebook_file: str, schema: bool, syntax: bool, validate_all: bool):
192
+ """
193
+ Validate a workflow notebook.
194
+
195
+ Examples:
196
+
197
+ # Validate schema only
198
+ mcli workflow notebook validate notebook.json --schema
199
+
200
+ # Validate code syntax
201
+ mcli workflow notebook validate notebook.json --syntax
202
+
203
+ # Run all validations
204
+ mcli workflow notebook validate notebook.json --all
205
+ """
206
+ if validate_all:
207
+ schema = syntax = True
208
+ elif not (schema or syntax):
209
+ # Default to all if no specific validation requested
210
+ schema = syntax = True
211
+
212
+ notebook_path = Path(notebook_file)
213
+ validator = NotebookValidator()
214
+
215
+ try:
216
+ # Load notebook
217
+ notebook = WorkflowConverter.load_notebook_json(notebook_path)
218
+
219
+ all_valid = True
220
+
221
+ if schema:
222
+ info("Validating JSON schema...")
223
+ schema_valid = validator.validate_schema(notebook)
224
+ if schema_valid:
225
+ success(" Schema validation passed")
226
+ else:
227
+ error(" Schema validation failed")
228
+ for err in validator.schema_errors:
229
+ error(f" - {err}")
230
+ all_valid = False
231
+
232
+ if syntax:
233
+ info("Validating code syntax...")
234
+ syntax_valid = validator.validate_syntax(notebook)
235
+ if syntax_valid:
236
+ success(" Syntax validation passed")
237
+ else:
238
+ error(" Syntax validation failed")
239
+ for err in validator.syntax_errors:
240
+ error(f" - {err}")
241
+ all_valid = False
242
+
243
+ if all_valid:
244
+ success(f"\nNotebook is valid: {notebook_path}")
245
+ else:
246
+ error(f"\nNotebook has validation errors: {notebook_path}")
247
+ raise click.Abort()
248
+
249
+ except Exception as e:
250
+ error(f"Validation failed: {e}")
251
+ raise click.Abort()
252
+
253
+
254
+ @notebook.command(name="info")
255
+ @click.argument("notebook_file", type=click.Path(exists=True))
256
+ @click.option(
257
+ "--json",
258
+ "output_json",
259
+ is_flag=True,
260
+ help="Output as JSON",
261
+ )
262
+ def notebook_info(notebook_file: str, output_json: bool):
263
+ """
264
+ Display information about a workflow notebook.
265
+
266
+ Examples:
267
+
268
+ # Show notebook info
269
+ mcli workflow notebook info notebook.json
270
+
271
+ # Output as JSON
272
+ mcli workflow notebook info notebook.json --json
273
+ """
274
+ notebook_path = Path(notebook_file)
275
+
276
+ try:
277
+ notebook = WorkflowConverter.load_notebook_json(notebook_path)
278
+
279
+ if output_json:
280
+ # Output as JSON
281
+ info_data = {
282
+ "name": notebook.metadata.mcli.name,
283
+ "description": notebook.metadata.mcli.description,
284
+ "group": notebook.metadata.mcli.group,
285
+ "version": notebook.metadata.mcli.version,
286
+ "language": notebook.metadata.mcli.language.value,
287
+ "total_cells": len(notebook.cells),
288
+ "code_cells": len(notebook.code_cells),
289
+ "markdown_cells": len(notebook.markdown_cells),
290
+ "created_at": notebook.metadata.mcli.created_at,
291
+ "updated_at": notebook.metadata.mcli.updated_at,
292
+ }
293
+ click.echo(json.dumps(info_data, indent=2))
294
+ else:
295
+ # Pretty print
296
+ info(f"Notebook: {notebook.metadata.mcli.name}")
297
+ if notebook.metadata.mcli.description:
298
+ info(f"Description: {notebook.metadata.mcli.description}")
299
+ if notebook.metadata.mcli.group:
300
+ info(f"Group: {notebook.metadata.mcli.group}")
301
+ info(f"Version: {notebook.metadata.mcli.version}")
302
+ info(f"Language: {notebook.metadata.mcli.language.value}")
303
+ info(f"\nCells:")
304
+ info(f" Total: {len(notebook.cells)}")
305
+ info(f" Code: {len(notebook.code_cells)}")
306
+ info(f" Markdown: {len(notebook.markdown_cells)}")
307
+ if notebook.metadata.mcli.created_at:
308
+ info(f"\nCreated: {notebook.metadata.mcli.created_at}")
309
+ if notebook.metadata.mcli.updated_at:
310
+ info(f"Updated: {notebook.metadata.mcli.updated_at}")
311
+
312
+ except Exception as e:
313
+ error(f"Failed to read notebook: {e}")
314
+ raise click.Abort()
315
+
316
+
317
+ @notebook.command(name="create")
318
+ @click.argument("name")
319
+ @click.option(
320
+ "-d",
321
+ "--description",
322
+ default="",
323
+ help="Notebook description",
324
+ )
325
+ @click.option(
326
+ "-g",
327
+ "--group",
328
+ default=None,
329
+ help="Command group",
330
+ )
331
+ @click.option(
332
+ "-l",
333
+ "--language",
334
+ type=click.Choice(["python", "shell", "bash"]),
335
+ default="python",
336
+ help="Default language",
337
+ )
338
+ @click.option(
339
+ "-o",
340
+ "--output",
341
+ type=click.Path(),
342
+ help="Output file path",
343
+ )
344
+ def create(name: str, description: str, group: Optional[str], language: str, output: Optional[str]):
345
+ """
346
+ Create a new workflow notebook.
347
+
348
+ Examples:
349
+
350
+ # Create a new Python workflow notebook
351
+ mcli workflow notebook create my-workflow
352
+
353
+ # Create with description and group
354
+ mcli workflow notebook create my-workflow -d "My workflow" -g workflow
355
+ """
356
+ from .schema import CellLanguage, MCLIMetadata, NotebookMetadata
357
+
358
+ # Create notebook
359
+ mcli_meta = MCLIMetadata(
360
+ name=name,
361
+ description=description,
362
+ group=group,
363
+ language=CellLanguage(language),
364
+ )
365
+ notebook_meta = NotebookMetadata(mcli=mcli_meta)
366
+ notebook = WorkflowNotebook(metadata=notebook_meta)
367
+
368
+ # Add welcome markdown cell
369
+ notebook.add_markdown_cell(
370
+ f"# {name}\n\n{description}\n\n"
371
+ f"This is a workflow notebook. Add code cells below to define your workflow."
372
+ )
373
+
374
+ # Add example code cell
375
+ if language == "python":
376
+ example_code = '''"""
377
+ Example workflow cell.
378
+ """
379
+ import click
380
+
381
+ @click.command()
382
+ def hello():
383
+ """Example command"""
384
+ click.echo("Hello from workflow!")
385
+
386
+ if __name__ == "__main__":
387
+ hello()
388
+ '''
389
+ else:
390
+ example_code = """#!/usr/bin/env bash
391
+ # Example workflow shell script
392
+
393
+ echo "Hello from workflow!"
394
+ """
395
+
396
+ notebook.add_code_cell(example_code, CellLanguage(language))
397
+
398
+ # Determine output path
399
+ if output:
400
+ output_path = Path(output)
401
+ else:
402
+ commands_dir = get_custom_commands_dir()
403
+ output_path = commands_dir / f"{name}.json"
404
+
405
+ # Save notebook
406
+ WorkflowConverter.save_notebook_json(notebook, output_path)
407
+ success(f"Created notebook: {output_path}")
408
+
409
+
410
+ @notebook.command(name="edit")
411
+ @click.argument("notebook_file", type=click.Path(exists=True))
412
+ @click.option(
413
+ "--port",
414
+ default=8888,
415
+ help="Server port for editor",
416
+ )
417
+ def edit(notebook_file: str, port: int):
418
+ """
419
+ Open a workflow notebook in the visual editor.
420
+
421
+ This launches a web server with Monaco editor for visual editing.
422
+
423
+ Examples:
424
+
425
+ # Open notebook in editor
426
+ mcli workflow notebook edit notebook.json
427
+
428
+ # Use custom port
429
+ mcli workflow notebook edit notebook.json --port 9000
430
+ """
431
+ # TODO: Implement web editor server (Phase 2)
432
+ warning("Visual editor is not yet implemented (coming in Phase 2)")
433
+ info(f"Would open editor for: {notebook_file} on port {port}")
434
+ info("\nFor now, you can:")
435
+ info(" 1. Edit the JSON file directly in your editor")
436
+ info(" 2. Use VSCode with Jupyter extension for .ipynb files")
437
+ info(" 3. Wait for the Monaco editor integration (Phase 2)")
438
+
439
+
440
+ if __name__ == "__main__":
441
+ notebook()