mcli-framework 7.10.1__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 (99) hide show
  1. mcli/lib/custom_commands.py +10 -0
  2. mcli/lib/optional_deps.py +240 -0
  3. mcli/workflow/git_commit/ai_service.py +13 -2
  4. mcli/workflow/notebook/converter.py +375 -0
  5. mcli/workflow/notebook/notebook_cmd.py +441 -0
  6. mcli/workflow/notebook/schema.py +402 -0
  7. mcli/workflow/notebook/validator.py +313 -0
  8. mcli/workflow/workflow.py +14 -0
  9. {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/METADATA +36 -2
  10. {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/RECORD +14 -94
  11. mcli/__init__.py +0 -160
  12. mcli/__main__.py +0 -14
  13. mcli/app/__init__.py +0 -23
  14. mcli/app/model/__init__.py +0 -0
  15. mcli/app/video/__init__.py +0 -5
  16. mcli/chat/__init__.py +0 -34
  17. mcli/lib/__init__.py +0 -0
  18. mcli/lib/api/__init__.py +0 -0
  19. mcli/lib/auth/__init__.py +0 -1
  20. mcli/lib/config/__init__.py +0 -1
  21. mcli/lib/erd/__init__.py +0 -25
  22. mcli/lib/files/__init__.py +0 -0
  23. mcli/lib/fs/__init__.py +0 -1
  24. mcli/lib/logger/__init__.py +0 -3
  25. mcli/lib/performance/__init__.py +0 -17
  26. mcli/lib/pickles/__init__.py +0 -1
  27. mcli/lib/secrets/__init__.py +0 -10
  28. mcli/lib/shell/__init__.py +0 -0
  29. mcli/lib/toml/__init__.py +0 -1
  30. mcli/lib/watcher/__init__.py +0 -0
  31. mcli/ml/__init__.py +0 -16
  32. mcli/ml/api/__init__.py +0 -30
  33. mcli/ml/api/routers/__init__.py +0 -27
  34. mcli/ml/auth/__init__.py +0 -41
  35. mcli/ml/backtesting/__init__.py +0 -33
  36. mcli/ml/cli/__init__.py +0 -5
  37. mcli/ml/config/__init__.py +0 -33
  38. mcli/ml/configs/__init__.py +0 -16
  39. mcli/ml/dashboard/__init__.py +0 -12
  40. mcli/ml/dashboard/components/__init__.py +0 -7
  41. mcli/ml/dashboard/pages/__init__.py +0 -6
  42. mcli/ml/data_ingestion/__init__.py +0 -29
  43. mcli/ml/database/__init__.py +0 -40
  44. mcli/ml/experimentation/__init__.py +0 -29
  45. mcli/ml/features/__init__.py +0 -39
  46. mcli/ml/features/political_features.py +0 -677
  47. mcli/ml/mlops/__init__.py +0 -19
  48. mcli/ml/models/__init__.py +0 -90
  49. mcli/ml/monitoring/__init__.py +0 -25
  50. mcli/ml/optimization/__init__.py +0 -27
  51. mcli/ml/predictions/__init__.py +0 -5
  52. mcli/ml/preprocessing/__init__.py +0 -24
  53. mcli/ml/preprocessing/politician_trading_preprocessor.py +0 -570
  54. mcli/ml/scripts/__init__.py +0 -1
  55. mcli/ml/serving/__init__.py +0 -1
  56. mcli/ml/trading/__init__.py +0 -63
  57. mcli/ml/training/__init__.py +0 -7
  58. mcli/mygroup/__init__.py +0 -3
  59. mcli/public/__init__.py +0 -1
  60. mcli/public/commands/__init__.py +0 -2
  61. mcli/self/__init__.py +0 -3
  62. mcli/workflow/__init__.py +0 -0
  63. mcli/workflow/daemon/__init__.py +0 -15
  64. mcli/workflow/dashboard/__init__.py +0 -5
  65. mcli/workflow/docker/__init__.py +0 -0
  66. mcli/workflow/file/__init__.py +0 -0
  67. mcli/workflow/gcloud/__init__.py +0 -1
  68. mcli/workflow/git_commit/__init__.py +0 -0
  69. mcli/workflow/interview/__init__.py +0 -0
  70. mcli/workflow/politician_trading/__init__.py +0 -4
  71. mcli/workflow/politician_trading/config.py +0 -134
  72. mcli/workflow/politician_trading/connectivity.py +0 -492
  73. mcli/workflow/politician_trading/data_sources.py +0 -654
  74. mcli/workflow/politician_trading/database.py +0 -412
  75. mcli/workflow/politician_trading/demo.py +0 -249
  76. mcli/workflow/politician_trading/models.py +0 -327
  77. mcli/workflow/politician_trading/monitoring.py +0 -413
  78. mcli/workflow/politician_trading/scrapers.py +0 -1074
  79. mcli/workflow/politician_trading/scrapers_california.py +0 -434
  80. mcli/workflow/politician_trading/scrapers_corporate_registry.py +0 -797
  81. mcli/workflow/politician_trading/scrapers_eu.py +0 -376
  82. mcli/workflow/politician_trading/scrapers_free_sources.py +0 -509
  83. mcli/workflow/politician_trading/scrapers_third_party.py +0 -373
  84. mcli/workflow/politician_trading/scrapers_uk.py +0 -378
  85. mcli/workflow/politician_trading/scrapers_us_states.py +0 -471
  86. mcli/workflow/politician_trading/seed_database.py +0 -520
  87. mcli/workflow/politician_trading/supabase_functions.py +0 -354
  88. mcli/workflow/politician_trading/workflow.py +0 -879
  89. mcli/workflow/registry/__init__.py +0 -0
  90. mcli/workflow/repo/__init__.py +0 -0
  91. mcli/workflow/scheduler/__init__.py +0 -25
  92. mcli/workflow/search/__init__.py +0 -0
  93. mcli/workflow/sync/__init__.py +0 -5
  94. mcli/workflow/videos/__init__.py +0 -1
  95. mcli/workflow/wakatime/__init__.py +0 -80
  96. {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/WHEEL +0 -0
  97. {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/entry_points.txt +0 -0
  98. {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/licenses/LICENSE +0 -0
  99. {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,313 @@
1
+ """
2
+ Validation utilities for workflow notebooks.
3
+
4
+ Provides validation for:
5
+ - JSON schema compliance
6
+ - Code syntax checking
7
+ - Shell script validation
8
+ - MCLI API validation
9
+ """
10
+
11
+ import ast
12
+ import subprocess
13
+ import tempfile
14
+ from pathlib import Path
15
+ from typing import Any, Dict, List, Optional
16
+
17
+ from mcli.lib.logger.logger import get_logger
18
+
19
+ from .schema import NOTEBOOK_SCHEMA, CellLanguage, CellType, WorkflowNotebook
20
+
21
+ logger = get_logger()
22
+
23
+
24
+ class NotebookValidator:
25
+ """Validator for workflow notebooks."""
26
+
27
+ def __init__(self):
28
+ self.schema_errors: List[str] = []
29
+ self.syntax_errors: List[str] = []
30
+
31
+ def validate_schema(self, notebook: WorkflowNotebook) -> bool:
32
+ """
33
+ Validate notebook against JSON schema.
34
+
35
+ Args:
36
+ notebook: WorkflowNotebook to validate
37
+
38
+ Returns:
39
+ True if valid, False otherwise
40
+ """
41
+ self.schema_errors = []
42
+
43
+ try:
44
+ import jsonschema
45
+
46
+ data = notebook.to_dict()
47
+ jsonschema.validate(instance=data, schema=NOTEBOOK_SCHEMA)
48
+ return True
49
+
50
+ except ImportError:
51
+ # jsonschema not installed, do basic validation
52
+ logger.warning("jsonschema not installed, performing basic validation")
53
+ return self._basic_schema_validation(notebook)
54
+
55
+ except Exception as e:
56
+ self.schema_errors.append(str(e))
57
+ return False
58
+
59
+ def _basic_schema_validation(self, notebook: WorkflowNotebook) -> bool:
60
+ """Basic schema validation without jsonschema library."""
61
+ valid = True
62
+
63
+ # Check required fields
64
+ if not notebook.metadata.mcli.name:
65
+ self.schema_errors.append("Missing required field: metadata.mcli.name")
66
+ valid = False
67
+
68
+ if notebook.nbformat != 4:
69
+ self.schema_errors.append(f"Invalid nbformat: {notebook.nbformat} (expected 4)")
70
+ valid = False
71
+
72
+ # Validate cells
73
+ for i, cell in enumerate(notebook.cells):
74
+ if not cell.cell_type:
75
+ self.schema_errors.append(f"Cell {i}: Missing cell_type")
76
+ valid = False
77
+
78
+ if not cell.source and not isinstance(cell.source, (str, list)):
79
+ self.schema_errors.append(f"Cell {i}: Missing or invalid source")
80
+ valid = False
81
+
82
+ return valid
83
+
84
+ def validate_syntax(self, notebook: WorkflowNotebook) -> bool:
85
+ """
86
+ Validate code syntax in all code cells.
87
+
88
+ Args:
89
+ notebook: WorkflowNotebook to validate
90
+
91
+ Returns:
92
+ True if all code is syntactically valid, False otherwise
93
+ """
94
+ self.syntax_errors = []
95
+ all_valid = True
96
+
97
+ for i, cell in enumerate(notebook.cells):
98
+ if cell.cell_type != CellType.CODE:
99
+ continue
100
+
101
+ language = cell.language
102
+ code = cell.source_text
103
+
104
+ if language == CellLanguage.PYTHON:
105
+ if not self._validate_python_syntax(code, i):
106
+ all_valid = False
107
+
108
+ elif language in (CellLanguage.SHELL, CellLanguage.BASH, CellLanguage.ZSH):
109
+ if not self._validate_shell_syntax(code, i):
110
+ all_valid = False
111
+
112
+ return all_valid
113
+
114
+ def _validate_python_syntax(self, code: str, cell_index: int) -> bool:
115
+ """Validate Python code syntax."""
116
+ try:
117
+ ast.parse(code)
118
+ return True
119
+ except SyntaxError as e:
120
+ self.syntax_errors.append(
121
+ f"Cell {cell_index} (Python): Syntax error at line {e.lineno}: {e.msg}"
122
+ )
123
+ return False
124
+ except Exception as e:
125
+ self.syntax_errors.append(f"Cell {cell_index} (Python): {str(e)}")
126
+ return False
127
+
128
+ def _validate_shell_syntax(self, code: str, cell_index: int) -> bool:
129
+ """Validate shell script syntax using bash -n."""
130
+ try:
131
+ # Create temporary file with shell script
132
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete=False) as f:
133
+ f.write(code)
134
+ temp_path = f.name
135
+
136
+ try:
137
+ # Use bash -n to check syntax without executing
138
+ result = subprocess.run(
139
+ ["bash", "-n", temp_path],
140
+ capture_output=True,
141
+ text=True,
142
+ timeout=5,
143
+ )
144
+
145
+ if result.returncode != 0:
146
+ error_msg = result.stderr.strip()
147
+ self.syntax_errors.append(f"Cell {cell_index} (Shell): {error_msg}")
148
+ return False
149
+
150
+ return True
151
+
152
+ finally:
153
+ # Clean up temp file
154
+ Path(temp_path).unlink(missing_ok=True)
155
+
156
+ except subprocess.TimeoutExpired:
157
+ self.syntax_errors.append(f"Cell {cell_index} (Shell): Validation timeout")
158
+ return False
159
+ except Exception as e:
160
+ self.syntax_errors.append(f"Cell {cell_index} (Shell): {str(e)}")
161
+ return False
162
+
163
+ def validate_mcli_apis(self, notebook: WorkflowNotebook) -> bool:
164
+ """
165
+ Validate MCLI API usage in code cells.
166
+
167
+ This checks for:
168
+ - Proper Click decorator usage
169
+ - MCLI library imports
170
+ - Common API patterns
171
+
172
+ Args:
173
+ notebook: WorkflowNotebook to validate
174
+
175
+ Returns:
176
+ True if API usage is valid, False otherwise
177
+ """
178
+ # TODO: Implement MCLI-specific API validation
179
+ # This could check for:
180
+ # - @click.command() or @click.group() decorators
181
+ # - Proper import statements
182
+ # - Common anti-patterns
183
+ return True
184
+
185
+ def get_all_errors(self) -> List[str]:
186
+ """Get all validation errors."""
187
+ return self.schema_errors + self.syntax_errors
188
+
189
+
190
+ class CodeLinter:
191
+ """Linter for workflow notebook code."""
192
+
193
+ def __init__(self):
194
+ self.issues: List[Dict[str, any]] = []
195
+
196
+ def lint_python(self, code: str) -> List[Dict[str, any]]:
197
+ """
198
+ Lint Python code using available linters.
199
+
200
+ Tries to use (in order):
201
+ 1. flake8
202
+ 2. pylint
203
+ 3. Basic AST-based checks
204
+
205
+ Returns:
206
+ List of lint issues
207
+ """
208
+ self.issues = []
209
+
210
+ # Try flake8
211
+ try:
212
+ import flake8.api.legacy as flake8_api
213
+
214
+ style_guide = flake8_api.get_style_guide()
215
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
216
+ f.write(code)
217
+ temp_path = f.name
218
+
219
+ try:
220
+ report = style_guide.check_files([temp_path])
221
+ # Convert flake8 results to our format
222
+ # (this is simplified - actual implementation would parse flake8 output)
223
+ if report.total_errors > 0:
224
+ self.issues.append(
225
+ {
226
+ "severity": "warning",
227
+ "message": f"Found {report.total_errors} style issues",
228
+ "line": 0,
229
+ }
230
+ )
231
+ finally:
232
+ Path(temp_path).unlink(missing_ok=True)
233
+
234
+ except ImportError:
235
+ # flake8 not available, try basic checks
236
+ self._basic_python_lint(code)
237
+
238
+ return self.issues
239
+
240
+ def _basic_python_lint(self, code: str):
241
+ """Basic Python linting using AST."""
242
+ try:
243
+ tree = ast.parse(code)
244
+
245
+ # Check for common issues
246
+ for node in ast.walk(tree):
247
+ # Check for unused imports (simplified)
248
+ if isinstance(node, ast.Import):
249
+ # TODO: Check if imports are actually used
250
+ pass
251
+
252
+ # Check for bare except
253
+ if isinstance(node, ast.ExceptHandler) and node.type is None:
254
+ self.issues.append(
255
+ {
256
+ "severity": "warning",
257
+ "message": "Bare except clause - consider specifying exception type",
258
+ "line": node.lineno,
259
+ }
260
+ )
261
+
262
+ except SyntaxError:
263
+ # Already caught by syntax validation
264
+ pass
265
+
266
+ def lint_shell(self, code: str) -> List[Dict[str, any]]:
267
+ """
268
+ Lint shell script using shellcheck if available.
269
+
270
+ Returns:
271
+ List of lint issues
272
+ """
273
+ self.issues = []
274
+
275
+ try:
276
+ # Create temporary file
277
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete=False) as f:
278
+ f.write(code)
279
+ temp_path = f.name
280
+
281
+ try:
282
+ # Try to use shellcheck
283
+ result = subprocess.run(
284
+ ["shellcheck", "-f", "json", temp_path],
285
+ capture_output=True,
286
+ text=True,
287
+ timeout=10,
288
+ )
289
+
290
+ if result.stdout:
291
+ import json
292
+
293
+ issues = json.loads(result.stdout)
294
+ self.issues = [
295
+ {
296
+ "severity": issue.get("level", "warning"),
297
+ "message": issue.get("message", ""),
298
+ "line": issue.get("line", 0),
299
+ "code": issue.get("code", ""),
300
+ }
301
+ for issue in issues
302
+ ]
303
+
304
+ finally:
305
+ Path(temp_path).unlink(missing_ok=True)
306
+
307
+ except FileNotFoundError:
308
+ # shellcheck not installed
309
+ logger.debug("shellcheck not found, skipping shell linting")
310
+ except Exception as e:
311
+ logger.warning(f"Shell linting failed: {e}")
312
+
313
+ return self.issues
mcli/workflow/workflow.py CHANGED
@@ -14,5 +14,19 @@ def workflow():
14
14
  pass
15
15
 
16
16
 
17
+ # Add notebook subcommand
18
+ try:
19
+ from mcli.workflow.notebook.notebook_cmd import notebook
20
+
21
+ workflow.add_command(notebook)
22
+ except ImportError as e:
23
+ # Notebook commands not available
24
+ import sys
25
+ from mcli.lib.logger.logger import get_logger
26
+
27
+ logger = get_logger()
28
+ logger.debug(f"Notebook commands not available: {e}")
29
+
30
+
17
31
  if __name__ == "__main__":
18
32
  workflow()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcli-framework
3
- Version: 7.10.1
3
+ Version: 7.10.2
4
4
  Summary: Portable workflow framework - transform any script into a versioned, schedulable command. Store in ~/.mcli/commands/, version with lockfile, run as daemon or cron job.
5
5
  Author-email: Luis Fernandez de la Vara <luis@lefv.io>
6
6
  Maintainer-email: Luis Fernandez de la Vara <luis@lefv.io>
@@ -160,6 +160,11 @@ Dynamic: license-file
160
160
 
161
161
  # MCLI - Portable Workflow Framework
162
162
 
163
+ [![codecov](https://codecov.io/gh/gwicho38/mcli/branch/main/graph/badge.svg)](https://codecov.io/gh/gwicho38/mcli)
164
+ [![Tests](https://github.com/gwicho38/mcli/workflows/CI%2FCD%20Pipeline/badge.svg)](https://github.com/gwicho38/mcli/actions)
165
+ [![Python Version](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://www.python.org/downloads/)
166
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
167
+
163
168
  **Transform any script into a versioned, portable, schedulable workflow command.**
164
169
 
165
170
  MCLI is a modular CLI framework that lets you write scripts once and run them anywhere - as interactive commands, scheduled jobs, or background daemons. Your workflows live in `~/.mcli/commands/`, are versioned via lockfile, and completely decoupled from the engine source code.
@@ -170,6 +175,35 @@ Write a script. Store it. Version it. Run it anywhere. Schedule it. Share it.
170
175
 
171
176
  No coupling to the engine. No vendor lock-in. Just portable workflows that work.
172
177
 
178
+ ## 🚀 Visual Workflow Editing
179
+
180
+ Edit your workflow JSON files like Jupyter notebooks with our VSCode extension!
181
+
182
+ [![VSCode Extension](https://img.shields.io/badge/VSCode-Extension-blue?logo=visualstudiocode)](vscode-extension/)
183
+ [![Visual Editing](https://img.shields.io/badge/workflows-visual%20editing-brightgreen)](vscode-extension/)
184
+
185
+ **Features:**
186
+ - 📝 Cell-based editing (Jupyter-like interface)
187
+ - ⚡ Live code execution (Python, Shell, Bash, Zsh, Fish)
188
+ - 🎯 Monaco editor with IntelliSense
189
+ - 📊 Rich markdown documentation cells
190
+ - 💾 Files stay as `.json` (git-friendly)
191
+
192
+ **Quick Install:**
193
+ ```bash
194
+ # From VSCode Marketplace (pending publication)
195
+ code --install-extension gwicho38.mcli-framework
196
+
197
+ # Or install from VSIX
198
+ code --install-extension vscode-extension/mcli-framework-1.0.0.vsix
199
+ ```
200
+
201
+ **Learn More:**
202
+ - [Extension README](vscode-extension/README.md) - Features and usage
203
+ - [Visual Editing Guide](README-VISUAL-EDITING.md) - Quick start
204
+ - [Installation Guide](vscode-extension/INSTALL.md) - Detailed setup
205
+ - [Workflow Notebooks Docs](docs/workflow-notebooks.md) - Complete guide
206
+
173
207
  ## ⚡ Quick Start
174
208
 
175
209
  ### Installation
@@ -450,7 +484,7 @@ Available workflows:
450
484
  - **redis** - Redis cache management
451
485
  - **videos** - Video processing and overlay removal
452
486
  - **sync** - Multi-cloud synchronization
453
- - **politician-trading** - Financial data collection (specialized)
487
+ - **politician-trading** - Now available as standalone package: [politician-trading-tracker](https://github.com/gwicho38/politician-trading-tracker)
454
488
 
455
489
  ## 💡 Why MCLI?
456
490