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
@@ -1,23 +1,24 @@
1
1
  """CI/CD Pipeline Monitoring Dashboard"""
2
2
 
3
- import streamlit as st
4
- import pandas as pd
5
- import requests
6
3
  import os
7
4
  from datetime import datetime, timedelta
8
- import plotly.graph_objects as go
9
- import plotly.express as px
10
5
  from typing import Optional
11
6
 
7
+ import pandas as pd
8
+ import plotly.express as px
9
+ import plotly.graph_objects as go
10
+ import requests
11
+ import streamlit as st
12
+
12
13
  # Import components
13
14
  try:
14
- from ..components.metrics import display_kpi_row, display_status_badge, display_health_indicator
15
- from ..components.charts import create_timeline_chart, create_status_pie_chart, render_chart
15
+ from ..components.charts import create_status_pie_chart, create_timeline_chart, render_chart
16
+ from ..components.metrics import display_health_indicator, display_kpi_row, display_status_badge
16
17
  from ..components.tables import display_filterable_dataframe, export_dataframe
17
18
  except ImportError:
18
19
  # Fallback for when imported outside package context
19
- from components.metrics import display_kpi_row, display_status_badge, display_health_indicator
20
- from components.charts import create_timeline_chart, create_status_pie_chart, render_chart
20
+ from components.charts import create_status_pie_chart, create_timeline_chart, render_chart
21
+ from components.metrics import display_health_indicator, display_kpi_row, display_status_badge
21
22
  from components.tables import display_filterable_dataframe, export_dataframe
22
23
 
23
24
 
@@ -65,21 +66,27 @@ def create_mock_cicd_data() -> pd.DataFrame:
65
66
 
66
67
  data = []
67
68
  for i in range(50):
68
- start_time = datetime.now() - timedelta(days=random.randint(0, 30), hours=random.randint(0, 23))
69
+ start_time = datetime.now() - timedelta(
70
+ days=random.randint(0, 30), hours=random.randint(0, 23)
71
+ )
69
72
  duration = random.randint(60, 600) # seconds
70
73
  status = random.choices(statuses, weights=[70, 15, 10, 5])[0]
71
74
 
72
- data.append({
73
- "id": f"build-{i+1}",
74
- "pipeline_name": random.choice(pipelines),
75
- "branch": random.choice(branches),
76
- "status": status,
77
- "started_at": start_time.isoformat(),
78
- "duration_sec": duration if status != "running" else None,
79
- "commit_sha": f"{random.randint(1000000, 9999999):07x}",
80
- "triggered_by": random.choice(["github-webhook", "manual", "schedule"]),
81
- "success_rate": random.uniform(0.7, 1.0) if status == "success" else random.uniform(0, 0.5)
82
- })
75
+ data.append(
76
+ {
77
+ "id": f"build-{i+1}",
78
+ "pipeline_name": random.choice(pipelines),
79
+ "branch": random.choice(branches),
80
+ "status": status,
81
+ "started_at": start_time.isoformat(),
82
+ "duration_sec": duration if status != "running" else None,
83
+ "commit_sha": f"{random.randint(1000000, 9999999):07x}",
84
+ "triggered_by": random.choice(["github-webhook", "manual", "schedule"]),
85
+ "success_rate": (
86
+ random.uniform(0.7, 1.0) if status == "success" else random.uniform(0, 0.5)
87
+ ),
88
+ }
89
+ )
83
90
 
84
91
  return pd.DataFrame(data)
85
92
 
@@ -104,8 +111,20 @@ def fetch_webhooks() -> list:
104
111
 
105
112
  # Return mock data
106
113
  return [
107
- {"id": "wh-1", "name": "GitHub Main", "url": "https://github.com/user/repo", "events": ["push", "pull_request"], "active": True},
108
- {"id": "wh-2", "name": "GitLab CI", "url": "https://gitlab.com/user/repo", "events": ["push"], "active": True},
114
+ {
115
+ "id": "wh-1",
116
+ "name": "GitHub Main",
117
+ "url": "https://github.com/user/repo",
118
+ "events": ["push", "pull_request"],
119
+ "active": True,
120
+ },
121
+ {
122
+ "id": "wh-2",
123
+ "name": "GitLab CI",
124
+ "url": "https://gitlab.com/user/repo",
125
+ "events": ["push"],
126
+ "active": True,
127
+ },
109
128
  ]
110
129
 
111
130
 
@@ -125,6 +144,7 @@ def show_cicd_dashboard():
125
144
 
126
145
  if auto_refresh:
127
146
  from streamlit_autorefresh import st_autorefresh
147
+
128
148
  # Auto-refresh every 30 seconds
129
149
  st_autorefresh(interval=30000, key="cicd_refresh")
130
150
 
@@ -155,10 +175,18 @@ def show_cicd_dashboard():
155
175
 
156
176
  metrics = {
157
177
  "Total Builds": {"value": total_builds, "icon": "📦"},
158
- "Success Rate": {"value": f"{success_rate:.1f}%", "delta": "+5.2%", "delta_color": "normal", "icon": "✅"},
178
+ "Success Rate": {
179
+ "value": f"{success_rate:.1f}%",
180
+ "delta": "+5.2%",
181
+ "delta_color": "normal",
182
+ "icon": "✅",
183
+ },
159
184
  "Failed Builds": {"value": failed_builds, "icon": "❌"},
160
185
  "Running": {"value": running_builds, "icon": "🔵"},
161
- "Avg Duration": {"value": f"{avg_duration:.0f}s" if pd.notna(avg_duration) else "N/A", "icon": "⏱️"}
186
+ "Avg Duration": {
187
+ "value": f"{avg_duration:.0f}s" if pd.notna(avg_duration) else "N/A",
188
+ "icon": "⏱️",
189
+ },
162
190
  }
163
191
 
164
192
  display_kpi_row(metrics, columns=5)
@@ -166,7 +194,9 @@ def show_cicd_dashboard():
166
194
  st.divider()
167
195
 
168
196
  # === Tabs for different views ===
169
- tab1, tab2, tab3, tab4 = st.tabs(["📈 Overview", "🔍 Build History", "🔔 Webhooks", "⚙️ Configuration"])
197
+ tab1, tab2, tab3, tab4 = st.tabs(
198
+ ["📈 Overview", "🔍 Build History", "🔔 Webhooks", "⚙️ Configuration"]
199
+ )
170
200
 
171
201
  with tab1:
172
202
  show_cicd_overview(builds_df)
@@ -199,9 +229,9 @@ def show_cicd_overview(builds_df: pd.DataFrame):
199
229
  fig = px.bar(
200
230
  x=pipeline_counts.values,
201
231
  y=pipeline_counts.index,
202
- orientation='h',
232
+ orientation="h",
203
233
  title="Top Pipelines by Build Count",
204
- labels={"x": "Number of Builds", "y": "Pipeline"}
234
+ labels={"x": "Number of Builds", "y": "Pipeline"},
205
235
  )
206
236
  render_chart(fig)
207
237
 
@@ -211,9 +241,11 @@ def show_cicd_overview(builds_df: pd.DataFrame):
211
241
  if "started_at" in builds_df.columns and "status" in builds_df.columns:
212
242
  # Group by date and calculate success rate
213
243
  builds_df["date"] = builds_df["started_at"].dt.date
214
- daily_stats = builds_df.groupby("date").agg({
215
- "status": lambda x: (x == "success").sum() / len(x) * 100
216
- }).reset_index()
244
+ daily_stats = (
245
+ builds_df.groupby("date")
246
+ .agg({"status": lambda x: (x == "success").sum() / len(x) * 100})
247
+ .reset_index()
248
+ )
217
249
  daily_stats.columns = ["date", "success_rate"]
218
250
 
219
251
  fig = px.line(
@@ -222,7 +254,7 @@ def show_cicd_overview(builds_df: pd.DataFrame):
222
254
  y="success_rate",
223
255
  title="Daily Success Rate",
224
256
  labels={"date": "Date", "success_rate": "Success Rate (%)"},
225
- markers=True
257
+ markers=True,
226
258
  )
227
259
  fig.add_hline(y=90, line_dash="dash", line_color="green", annotation_text="Target: 90%")
228
260
  render_chart(fig)
@@ -242,7 +274,7 @@ def show_cicd_overview(builds_df: pd.DataFrame):
242
274
  y="duration_min",
243
275
  color="pipeline_name",
244
276
  title="Build Duration Over Time",
245
- labels={"started_at": "Time", "duration_min": "Duration (minutes)"}
277
+ labels={"started_at": "Time", "duration_min": "Duration (minutes)"},
246
278
  )
247
279
  render_chart(fig)
248
280
 
@@ -256,13 +288,11 @@ def show_build_history(builds_df: pd.DataFrame):
256
288
  filter_config = {
257
289
  "pipeline_name": "multiselect",
258
290
  "status": "multiselect",
259
- "branch": "multiselect"
291
+ "branch": "multiselect",
260
292
  }
261
293
 
262
294
  filtered_df = display_filterable_dataframe(
263
- builds_df,
264
- filter_columns=filter_config,
265
- key_prefix="cicd_filter"
295
+ builds_df, filter_columns=filter_config, key_prefix="cicd_filter"
266
296
  )
267
297
 
268
298
  # Export option
@@ -274,7 +304,9 @@ def show_build_history(builds_df: pd.DataFrame):
274
304
 
275
305
  if not filtered_df.empty:
276
306
  for _, build in filtered_df.head(20).iterrows():
277
- with st.expander(f"{build.get('pipeline_name', 'Unknown')} - {build.get('commit_sha', 'Unknown')[:7]} - {display_status_badge(build.get('status', 'unknown'), 'small')}"):
307
+ with st.expander(
308
+ f"{build.get('pipeline_name', 'Unknown')} - {build.get('commit_sha', 'Unknown')[:7]} - {display_status_badge(build.get('status', 'unknown'), 'small')}"
309
+ ):
278
310
  col1, col2 = st.columns(2)
279
311
 
280
312
  with col1:
@@ -284,20 +316,27 @@ def show_build_history(builds_df: pd.DataFrame):
284
316
  st.markdown(f"**Triggered By:** {build.get('triggered_by', 'N/A')}")
285
317
 
286
318
  with col2:
287
- st.markdown(f"**Status:** {display_status_badge(build.get('status', 'unknown'), 'small')}")
319
+ st.markdown(
320
+ f"**Status:** {display_status_badge(build.get('status', 'unknown'), 'small')}"
321
+ )
288
322
  st.markdown(f"**Started:** {build.get('started_at', 'N/A')}")
289
- if pd.notna(build.get('duration_sec')):
290
- st.markdown(f"**Duration:** {build['duration_sec']}s ({build['duration_sec']/60:.1f}m)")
323
+ if pd.notna(build.get("duration_sec")):
324
+ st.markdown(
325
+ f"**Duration:** {build['duration_sec']}s ({build['duration_sec']/60:.1f}m)"
326
+ )
291
327
 
292
328
  # Mock logs
293
329
  if st.button(f"View Logs", key=f"logs_{build.get('id')}"):
294
- st.code(f"""
330
+ st.code(
331
+ f"""
295
332
  [INFO] Starting build for {build.get('pipeline_name')}
296
333
  [INFO] Checking out branch: {build.get('branch')}
297
334
  [INFO] Installing dependencies...
298
335
  [INFO] Running tests...
299
336
  [INFO] Build {'completed successfully' if build.get('status') == 'success' else 'failed'}
300
- """, language="bash")
337
+ """,
338
+ language="bash",
339
+ )
301
340
 
302
341
 
303
342
  def show_webhooks_config():
@@ -312,7 +351,9 @@ def show_webhooks_config():
312
351
  return
313
352
 
314
353
  for webhook in webhooks:
315
- with st.expander(f"{webhook['name']} - {'✅ Active' if webhook['active'] else '❌ Inactive'}"):
354
+ with st.expander(
355
+ f"{webhook['name']} - {'✅ Active' if webhook['active'] else '❌ Inactive'}"
356
+ ):
316
357
  st.markdown(f"**URL:** `{webhook['url']}`")
317
358
  st.markdown(f"**Events:** {', '.join(webhook['events'])}")
318
359
  st.markdown(f"**Status:** {'Active' if webhook['active'] else 'Inactive'}")
@@ -351,8 +392,12 @@ def show_cicd_configuration():
351
392
  with st.form("cicd_config"):
352
393
  st.markdown("#### Pipeline Settings")
353
394
 
354
- max_concurrent_builds = st.number_input("Max Concurrent Builds", min_value=1, max_value=10, value=3)
355
- build_timeout = st.number_input("Build Timeout (minutes)", min_value=5, max_value=120, value=30)
395
+ max_concurrent_builds = st.number_input(
396
+ "Max Concurrent Builds", min_value=1, max_value=10, value=3
397
+ )
398
+ build_timeout = st.number_input(
399
+ "Build Timeout (minutes)", min_value=5, max_value=120, value=30
400
+ )
356
401
  retry_failed_builds = st.checkbox("Auto-retry Failed Builds", value=True)
357
402
  max_retries = st.number_input("Max Retries", min_value=1, max_value=5, value=2)
358
403
 
@@ -365,17 +410,19 @@ def show_cicd_configuration():
365
410
 
366
411
  if submitted:
367
412
  st.success("✅ Configuration saved successfully!")
368
- st.json({
369
- "max_concurrent_builds": max_concurrent_builds,
370
- "build_timeout_minutes": build_timeout,
371
- "retry_failed_builds": retry_failed_builds,
372
- "max_retries": max_retries,
373
- "notifications": {
374
- "on_success": notify_on_success,
375
- "on_failure": notify_on_failure,
376
- "email": notification_email
413
+ st.json(
414
+ {
415
+ "max_concurrent_builds": max_concurrent_builds,
416
+ "build_timeout_minutes": build_timeout,
417
+ "retry_failed_builds": retry_failed_builds,
418
+ "max_retries": max_retries,
419
+ "notifications": {
420
+ "on_success": notify_on_success,
421
+ "on_failure": notify_on_failure,
422
+ "email": notification_email,
423
+ },
377
424
  }
378
- })
425
+ )
379
426
 
380
427
 
381
428
  if __name__ == "__main__":
@@ -1,36 +1,44 @@
1
1
  """Debug Dependencies - Diagnostic page for troubleshooting installation issues"""
2
2
 
3
- import streamlit as st
4
- import sys
5
3
  import subprocess
4
+ import sys
6
5
  from pathlib import Path
7
6
  from typing import Dict, List, Tuple
8
7
 
8
+ import streamlit as st
9
+
9
10
 
10
11
  def show_debug_dependencies():
11
12
  """Diagnostic page for dependency debugging"""
12
13
 
13
14
  st.title("🔍 Dependency Diagnostics")
14
- st.markdown("""
15
+ st.markdown(
16
+ """
15
17
  This page helps diagnose why certain dependencies (like alpaca-py) may not be installing correctly.
16
- """)
18
+ """
19
+ )
17
20
 
18
21
  # Python environment info
19
22
  st.header("🐍 Python Environment")
20
23
 
21
24
  col1, col2 = st.columns(2)
22
25
  with col1:
23
- st.metric("Python Version", f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
26
+ st.metric(
27
+ "Python Version",
28
+ f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
29
+ )
24
30
  with col2:
25
31
  st.metric("Platform", sys.platform)
26
32
 
27
33
  with st.expander("📋 Detailed Python Info", expanded=False):
28
- st.code(f"""
34
+ st.code(
35
+ f"""
29
36
  Python Version: {sys.version}
30
37
  Python Path: {sys.executable}
31
38
  Prefix: {sys.prefix}
32
39
  Platform: {sys.platform}
33
- """)
40
+ """
41
+ )
34
42
 
35
43
  # Check Python paths
36
44
  st.header("📁 Python Paths")
@@ -92,9 +100,11 @@ Platform: {sys.platform}
92
100
  # Detailed alpaca-py investigation
93
101
  st.header("🔬 Alpaca-py Deep Dive")
94
102
 
95
- st.markdown("""
103
+ st.markdown(
104
+ """
96
105
  Attempting to import alpaca-py components individually to identify specific failure points.
97
- """)
106
+ """
107
+ )
98
108
 
99
109
  alpaca_submodules = [
100
110
  "alpaca",
@@ -146,20 +156,14 @@ Platform: {sys.platform}
146
156
 
147
157
  for pm_name, pm_command in package_managers:
148
158
  try:
149
- result = subprocess.run(
150
- pm_command,
151
- capture_output=True,
152
- text=True,
153
- timeout=10
154
- )
159
+ result = subprocess.run(pm_command, capture_output=True, text=True, timeout=10)
155
160
 
156
161
  if result.returncode == 0:
157
162
  packages_found = True
158
163
 
159
164
  # Search for alpaca-related packages
160
165
  alpaca_packages = [
161
- line for line in result.stdout.split("\n")
162
- if "alpaca" in line.lower()
166
+ line for line in result.stdout.split("\n") if "alpaca" in line.lower()
163
167
  ]
164
168
 
165
169
  if alpaca_packages:
@@ -193,12 +197,7 @@ Platform: {sys.platform}
193
197
 
194
198
  for pm_name, pm_command in show_commands:
195
199
  try:
196
- result = subprocess.run(
197
- pm_command,
198
- capture_output=True,
199
- text=True,
200
- timeout=10
201
- )
200
+ result = subprocess.run(pm_command, capture_output=True, text=True, timeout=10)
202
201
 
203
202
  if result.returncode == 0:
204
203
  package_info_found = True
@@ -208,6 +207,7 @@ Platform: {sys.platform}
208
207
  # Try to get the version from import
209
208
  try:
210
209
  import alpaca
210
+
211
211
  if hasattr(alpaca, "__version__"):
212
212
  st.info(f"📦 Alpaca version from import: {alpaca.__version__}")
213
213
  except:
@@ -224,6 +224,7 @@ Platform: {sys.platform}
224
224
  # Check if imports work anyway
225
225
  try:
226
226
  import alpaca
227
+
227
228
  st.success("✅ Alpaca module imports successfully!")
228
229
  if hasattr(alpaca, "__version__"):
229
230
  st.info(f"📦 Version from import: {alpaca.__version__}")
@@ -276,6 +277,7 @@ Platform: {sys.platform}
276
277
  st.markdown("Checking for relevant environment variables:")
277
278
 
278
279
  import os
280
+
279
281
  for var in env_vars_to_check:
280
282
  value = os.environ.get(var)
281
283
  if value:
@@ -296,13 +298,15 @@ Platform: {sys.platform}
296
298
 
297
299
  if is_cloud:
298
300
  st.success("✅ Running on Streamlit Cloud")
299
- st.info("""
301
+ st.info(
302
+ """
300
303
  **Note:** On Streamlit Cloud, packages are installed from requirements.txt during deployment.
301
304
  If alpaca-py is not installed, check:
302
305
  1. requirements.txt has correct package name and version
303
306
  2. Package has no conflicting dependencies
304
307
  3. Deployment logs for installation errors
305
- """)
308
+ """
309
+ )
306
310
  else:
307
311
  st.info("ℹ️ Running locally (not Streamlit Cloud)")
308
312
 
@@ -328,7 +332,8 @@ Platform: {sys.platform}
328
332
  st.header("🛠️ Troubleshooting Guide")
329
333
 
330
334
  with st.expander("🔧 Common Solutions", expanded=True):
331
- st.markdown("""
335
+ st.markdown(
336
+ """
332
337
  ### If alpaca-py import fails:
333
338
 
334
339
  #### 1. Check Requirements.txt
@@ -372,7 +377,8 @@ Platform: {sys.platform}
372
377
  pip uninstall alpaca-py -y
373
378
  pip install alpaca-py>=0.20.0
374
379
  ```
375
- """)
380
+ """
381
+ )
376
382
 
377
383
  # Export diagnostics
378
384
  st.header("💾 Export Diagnostics")
@@ -394,7 +400,7 @@ Generated: {pd.Timestamp.now()}
394
400
  diagnostics += f"\n- {module_name}: {status}\n Info: {info}\n"
395
401
 
396
402
  diagnostics += "\n## Installed Packages\n"
397
- if 'result' in locals() and result.returncode == 0:
403
+ if "result" in locals() and result.returncode == 0:
398
404
  diagnostics += result.stdout
399
405
 
400
406
  st.code(diagnostics)
@@ -403,4 +409,5 @@ Generated: {pd.Timestamp.now()}
403
409
 
404
410
  if __name__ == "__main__":
405
411
  import pandas as pd
412
+
406
413
  show_debug_dependencies()