mcli-framework 7.1.0__py3-none-any.whl → 7.1.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 (94) hide show
  1. mcli/app/completion_cmd.py +59 -49
  2. mcli/app/completion_helpers.py +60 -138
  3. mcli/app/logs_cmd.py +46 -13
  4. mcli/app/main.py +17 -14
  5. mcli/app/model_cmd.py +19 -4
  6. mcli/chat/chat.py +3 -2
  7. mcli/lib/search/cached_vectorizer.py +1 -0
  8. mcli/lib/services/data_pipeline.py +12 -5
  9. mcli/lib/services/lsh_client.py +69 -58
  10. mcli/ml/api/app.py +28 -36
  11. mcli/ml/api/middleware.py +8 -16
  12. mcli/ml/api/routers/admin_router.py +3 -1
  13. mcli/ml/api/routers/auth_router.py +32 -56
  14. mcli/ml/api/routers/backtest_router.py +3 -1
  15. mcli/ml/api/routers/data_router.py +3 -1
  16. mcli/ml/api/routers/model_router.py +35 -74
  17. mcli/ml/api/routers/monitoring_router.py +3 -1
  18. mcli/ml/api/routers/portfolio_router.py +3 -1
  19. mcli/ml/api/routers/prediction_router.py +60 -65
  20. mcli/ml/api/routers/trade_router.py +6 -2
  21. mcli/ml/api/routers/websocket_router.py +12 -9
  22. mcli/ml/api/schemas.py +10 -2
  23. mcli/ml/auth/auth_manager.py +49 -114
  24. mcli/ml/auth/models.py +30 -15
  25. mcli/ml/auth/permissions.py +12 -19
  26. mcli/ml/backtesting/backtest_engine.py +134 -108
  27. mcli/ml/backtesting/performance_metrics.py +142 -108
  28. mcli/ml/cache.py +12 -18
  29. mcli/ml/cli/main.py +37 -23
  30. mcli/ml/config/settings.py +29 -12
  31. mcli/ml/dashboard/app.py +122 -130
  32. mcli/ml/dashboard/app_integrated.py +283 -152
  33. mcli/ml/dashboard/app_supabase.py +176 -108
  34. mcli/ml/dashboard/app_training.py +212 -206
  35. mcli/ml/dashboard/cli.py +14 -5
  36. mcli/ml/data_ingestion/api_connectors.py +51 -81
  37. mcli/ml/data_ingestion/data_pipeline.py +127 -125
  38. mcli/ml/data_ingestion/stream_processor.py +72 -80
  39. mcli/ml/database/migrations/env.py +3 -2
  40. mcli/ml/database/models.py +112 -79
  41. mcli/ml/database/session.py +6 -5
  42. mcli/ml/experimentation/ab_testing.py +149 -99
  43. mcli/ml/features/ensemble_features.py +9 -8
  44. mcli/ml/features/political_features.py +6 -5
  45. mcli/ml/features/recommendation_engine.py +15 -14
  46. mcli/ml/features/stock_features.py +7 -6
  47. mcli/ml/features/test_feature_engineering.py +8 -7
  48. mcli/ml/logging.py +10 -15
  49. mcli/ml/mlops/data_versioning.py +57 -64
  50. mcli/ml/mlops/experiment_tracker.py +49 -41
  51. mcli/ml/mlops/model_serving.py +59 -62
  52. mcli/ml/mlops/pipeline_orchestrator.py +203 -149
  53. mcli/ml/models/base_models.py +8 -7
  54. mcli/ml/models/ensemble_models.py +6 -5
  55. mcli/ml/models/recommendation_models.py +7 -6
  56. mcli/ml/models/test_models.py +18 -14
  57. mcli/ml/monitoring/drift_detection.py +95 -74
  58. mcli/ml/monitoring/metrics.py +10 -22
  59. mcli/ml/optimization/portfolio_optimizer.py +172 -132
  60. mcli/ml/predictions/prediction_engine.py +235 -0
  61. mcli/ml/preprocessing/data_cleaners.py +6 -5
  62. mcli/ml/preprocessing/feature_extractors.py +7 -6
  63. mcli/ml/preprocessing/ml_pipeline.py +3 -2
  64. mcli/ml/preprocessing/politician_trading_preprocessor.py +11 -10
  65. mcli/ml/preprocessing/test_preprocessing.py +4 -4
  66. mcli/ml/scripts/populate_sample_data.py +36 -16
  67. mcli/ml/tasks.py +82 -83
  68. mcli/ml/tests/test_integration.py +86 -76
  69. mcli/ml/tests/test_training_dashboard.py +169 -142
  70. mcli/mygroup/test_cmd.py +2 -1
  71. mcli/self/self_cmd.py +38 -18
  72. mcli/self/test_cmd.py +2 -1
  73. mcli/workflow/dashboard/dashboard_cmd.py +13 -6
  74. mcli/workflow/lsh_integration.py +46 -58
  75. mcli/workflow/politician_trading/commands.py +576 -427
  76. mcli/workflow/politician_trading/config.py +7 -7
  77. mcli/workflow/politician_trading/connectivity.py +35 -33
  78. mcli/workflow/politician_trading/data_sources.py +72 -71
  79. mcli/workflow/politician_trading/database.py +18 -16
  80. mcli/workflow/politician_trading/demo.py +4 -3
  81. mcli/workflow/politician_trading/models.py +5 -5
  82. mcli/workflow/politician_trading/monitoring.py +13 -13
  83. mcli/workflow/politician_trading/scrapers.py +332 -224
  84. mcli/workflow/politician_trading/scrapers_california.py +116 -94
  85. mcli/workflow/politician_trading/scrapers_eu.py +70 -71
  86. mcli/workflow/politician_trading/scrapers_uk.py +118 -90
  87. mcli/workflow/politician_trading/scrapers_us_states.py +125 -92
  88. mcli/workflow/politician_trading/workflow.py +98 -71
  89. {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/METADATA +2 -2
  90. {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/RECORD +94 -93
  91. {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/WHEEL +0 -0
  92. {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/entry_points.txt +0 -0
  93. {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/licenses/LICENSE +0 -0
  94. {mcli_framework-7.1.0.dist-info → mcli_framework-7.1.2.dist-info}/top_level.txt +0 -0
@@ -1,46 +1,59 @@
1
1
  """Database models for ML system"""
2
2
 
3
3
  from datetime import datetime
4
- from typing import Optional, Dict, Any, List
5
4
  from enum import Enum as PyEnum
5
+ from typing import Any, Dict, List, Optional
6
6
  from uuid import uuid4
7
7
 
8
8
  from sqlalchemy import (
9
- Column, String, Integer, Float, DateTime, Boolean, Text,
10
- ForeignKey, JSON, Enum, Index, UniqueConstraint, CheckConstraint,
11
- Table, event, BigInteger
9
+ JSON,
10
+ BigInteger,
11
+ Boolean,
12
+ CheckConstraint,
13
+ Column,
14
+ DateTime,
15
+ Enum,
16
+ Float,
17
+ ForeignKey,
18
+ Index,
19
+ Integer,
20
+ String,
21
+ Table,
22
+ Text,
23
+ UniqueConstraint,
24
+ event,
12
25
  )
13
- from sqlalchemy.orm import declarative_base, relationship, validates
14
- from sqlalchemy.dialects.postgresql import UUID, ARRAY
26
+ from sqlalchemy.dialects.postgresql import ARRAY, UUID
15
27
  from sqlalchemy.ext.hybrid import hybrid_property
28
+ from sqlalchemy.orm import declarative_base, relationship, validates
16
29
  from sqlalchemy.sql import func
17
30
 
18
-
19
31
  Base = declarative_base()
20
32
 
21
33
 
22
34
  # Association tables for many-to-many relationships
23
35
  portfolio_stocks = Table(
24
- 'portfolio_stocks',
36
+ "portfolio_stocks",
25
37
  Base.metadata,
26
- Column('portfolio_id', UUID(as_uuid=True), ForeignKey('portfolios.id')),
27
- Column('stock_ticker', String, ForeignKey('stock_data.ticker')),
28
- Column('weight', Float, nullable=False),
29
- Column('shares', Integer, default=0),
30
- Column('entry_price', Float),
31
- Column('created_at', DateTime, default=datetime.utcnow),
38
+ Column("portfolio_id", UUID(as_uuid=True), ForeignKey("portfolios.id")),
39
+ Column("stock_ticker", String, ForeignKey("stock_data.ticker")),
40
+ Column("weight", Float, nullable=False),
41
+ Column("shares", Integer, default=0),
42
+ Column("entry_price", Float),
43
+ Column("created_at", DateTime, default=datetime.utcnow),
32
44
  )
33
45
 
34
46
  experiment_models = Table(
35
- 'experiment_models',
47
+ "experiment_models",
36
48
  Base.metadata,
37
- Column('experiment_id', UUID(as_uuid=True), ForeignKey('experiments.id')),
38
- Column('model_id', UUID(as_uuid=True), ForeignKey('models.id')),
49
+ Column("experiment_id", UUID(as_uuid=True), ForeignKey("experiments.id")),
50
+ Column("model_id", UUID(as_uuid=True), ForeignKey("models.id")),
39
51
  )
40
52
 
41
53
 
42
54
  class UserRole(PyEnum):
43
55
  """User role enumeration"""
56
+
44
57
  ADMIN = "admin"
45
58
  USER = "user"
46
59
  ANALYST = "analyst"
@@ -49,6 +62,7 @@ class UserRole(PyEnum):
49
62
 
50
63
  class ModelStatus(PyEnum):
51
64
  """Model status enumeration"""
65
+
52
66
  TRAINING = "training"
53
67
  TRAINED = "trained"
54
68
  DEPLOYED = "deployed"
@@ -58,6 +72,7 @@ class ModelStatus(PyEnum):
58
72
 
59
73
  class TradeType(PyEnum):
60
74
  """Trade type enumeration"""
75
+
61
76
  BUY = "buy"
62
77
  SELL = "sell"
63
78
  OPTION = "option"
@@ -65,6 +80,7 @@ class TradeType(PyEnum):
65
80
 
66
81
  class AlertType(PyEnum):
67
82
  """Alert type enumeration"""
83
+
68
84
  POLITICIAN_TRADE = "politician_trade"
69
85
  PRICE_MOVEMENT = "price_movement"
70
86
  VOLUME_SPIKE = "volume_spike"
@@ -74,7 +90,8 @@ class AlertType(PyEnum):
74
90
 
75
91
  class User(Base):
76
92
  """User model for authentication and authorization"""
77
- __tablename__ = 'users'
93
+
94
+ __tablename__ = "users"
78
95
 
79
96
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
80
97
  username = Column(String(50), unique=True, nullable=False, index=True)
@@ -102,22 +119,26 @@ class User(Base):
102
119
 
103
120
  # Constraints
104
121
  __table_args__ = (
105
- CheckConstraint("email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$'", name='valid_email'),
106
- Index('idx_user_active', 'is_active'),
122
+ CheckConstraint(
123
+ "email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$'", name="valid_email"
124
+ ),
125
+ Index("idx_user_active", "is_active"),
107
126
  )
108
127
 
109
- @validates('email')
128
+ @validates("email")
110
129
  def validate_email(self, key, email):
111
130
  """Validate email format"""
112
131
  import re
113
- if not re.match(r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$', email):
132
+
133
+ if not re.match(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$", email):
114
134
  raise ValueError("Invalid email format")
115
135
  return email.lower()
116
136
 
117
137
 
118
138
  class Politician(Base):
119
139
  """Politician information"""
120
- __tablename__ = 'politicians'
140
+
141
+ __tablename__ = "politicians"
121
142
 
122
143
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
123
144
  name = Column(String(100), nullable=False)
@@ -142,17 +163,18 @@ class Politician(Base):
142
163
 
143
164
  # Indexes
144
165
  __table_args__ = (
145
- Index('idx_politician_active', 'active'),
146
- Index('idx_politician_party_state', 'party', 'state'),
166
+ Index("idx_politician_active", "active"),
167
+ Index("idx_politician_party_state", "party", "state"),
147
168
  )
148
169
 
149
170
 
150
171
  class Trade(Base):
151
172
  """Political trading records"""
152
- __tablename__ = 'trades'
173
+
174
+ __tablename__ = "trades"
153
175
 
154
176
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
155
- politician_id = Column(UUID(as_uuid=True), ForeignKey('politicians.id'), nullable=False)
177
+ politician_id = Column(UUID(as_uuid=True), ForeignKey("politicians.id"), nullable=False)
156
178
 
157
179
  ticker = Column(String(10), nullable=False, index=True)
158
180
  trade_type = Column(Enum(TradeType), nullable=False)
@@ -175,10 +197,11 @@ class Trade(Base):
175
197
 
176
198
  # Indexes and constraints
177
199
  __table_args__ = (
178
- Index('idx_trade_ticker_date', 'ticker', 'disclosure_date'),
179
- Index('idx_trade_politician_date', 'politician_id', 'disclosure_date'),
180
- UniqueConstraint('politician_id', 'ticker', 'disclosure_date', 'trade_type',
181
- name='unique_trade'),
200
+ Index("idx_trade_ticker_date", "ticker", "disclosure_date"),
201
+ Index("idx_trade_politician_date", "politician_id", "disclosure_date"),
202
+ UniqueConstraint(
203
+ "politician_id", "ticker", "disclosure_date", "trade_type", name="unique_trade"
204
+ ),
182
205
  )
183
206
 
184
207
  @hybrid_property
@@ -191,7 +214,8 @@ class Trade(Base):
191
214
 
192
215
  class StockData(Base):
193
216
  """Stock market data"""
194
- __tablename__ = 'stock_data'
217
+
218
+ __tablename__ = "stock_data"
195
219
 
196
220
  ticker = Column(String(10), primary_key=True)
197
221
  company_name = Column(String(200))
@@ -234,20 +258,21 @@ class StockData(Base):
234
258
 
235
259
  # Indexes
236
260
  __table_args__ = (
237
- Index('idx_stock_sector_cap', 'sector', 'market_cap'),
238
- Index('idx_stock_updated', 'last_updated'),
261
+ Index("idx_stock_sector_cap", "sector", "market_cap"),
262
+ Index("idx_stock_updated", "last_updated"),
239
263
  )
240
264
 
241
265
 
242
266
  class Prediction(Base):
243
267
  """Model predictions"""
244
- __tablename__ = 'predictions'
268
+
269
+ __tablename__ = "predictions"
245
270
 
246
271
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
247
- model_id = Column(UUID(as_uuid=True), ForeignKey('models.id'), nullable=False)
248
- user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'))
272
+ model_id = Column(UUID(as_uuid=True), ForeignKey("models.id"), nullable=False)
273
+ user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"))
249
274
 
250
- ticker = Column(String(10), ForeignKey('stock_data.ticker'), nullable=False, index=True)
275
+ ticker = Column(String(10), ForeignKey("stock_data.ticker"), nullable=False, index=True)
251
276
 
252
277
  # Prediction details
253
278
  prediction_date = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
@@ -281,18 +306,19 @@ class Prediction(Base):
281
306
 
282
307
  # Indexes
283
308
  __table_args__ = (
284
- Index('idx_prediction_date_ticker', 'prediction_date', 'ticker'),
285
- Index('idx_prediction_model_date', 'model_id', 'prediction_date'),
286
- Index('idx_prediction_confidence', 'confidence_score'),
309
+ Index("idx_prediction_date_ticker", "prediction_date", "ticker"),
310
+ Index("idx_prediction_model_date", "model_id", "prediction_date"),
311
+ Index("idx_prediction_confidence", "confidence_score"),
287
312
  )
288
313
 
289
314
 
290
315
  class Portfolio(Base):
291
316
  """User portfolios"""
292
- __tablename__ = 'portfolios'
317
+
318
+ __tablename__ = "portfolios"
293
319
 
294
320
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
295
- user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
321
+ user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
296
322
 
297
323
  name = Column(String(100), nullable=False)
298
324
  description = Column(Text)
@@ -326,28 +352,29 @@ class Portfolio(Base):
326
352
 
327
353
  # Constraints
328
354
  __table_args__ = (
329
- UniqueConstraint('user_id', 'name', name='unique_user_portfolio'),
330
- Index('idx_portfolio_active', 'is_active'),
355
+ UniqueConstraint("user_id", "name", name="unique_user_portfolio"),
356
+ Index("idx_portfolio_active", "is_active"),
331
357
  )
332
358
 
333
359
 
334
360
  class Alert(Base):
335
361
  """User alerts and notifications"""
336
- __tablename__ = 'alerts'
362
+
363
+ __tablename__ = "alerts"
337
364
 
338
365
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
339
- user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
366
+ user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
340
367
 
341
368
  alert_type = Column(Enum(AlertType), nullable=False, index=True)
342
- severity = Column(String(10), default='info') # info, warning, critical
369
+ severity = Column(String(10), default="info") # info, warning, critical
343
370
 
344
371
  title = Column(String(200), nullable=False)
345
372
  message = Column(Text, nullable=False)
346
373
 
347
374
  # Related entities
348
375
  ticker = Column(String(10), index=True)
349
- politician_id = Column(UUID(as_uuid=True), ForeignKey('politicians.id'))
350
- portfolio_id = Column(UUID(as_uuid=True), ForeignKey('portfolios.id'))
376
+ politician_id = Column(UUID(as_uuid=True), ForeignKey("politicians.id"))
377
+ portfolio_id = Column(UUID(as_uuid=True), ForeignKey("portfolios.id"))
351
378
 
352
379
  is_read = Column(Boolean, default=False, index=True)
353
380
  is_sent = Column(Boolean, default=False)
@@ -363,18 +390,19 @@ class Alert(Base):
363
390
 
364
391
  # Indexes
365
392
  __table_args__ = (
366
- Index('idx_alert_user_unread', 'user_id', 'is_read'),
367
- Index('idx_alert_created', 'created_at'),
393
+ Index("idx_alert_user_unread", "user_id", "is_read"),
394
+ Index("idx_alert_created", "created_at"),
368
395
  )
369
396
 
370
397
 
371
398
  class BacktestResult(Base):
372
399
  """Backtesting results"""
373
- __tablename__ = 'backtest_results'
400
+
401
+ __tablename__ = "backtest_results"
374
402
 
375
403
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
376
- model_id = Column(UUID(as_uuid=True), ForeignKey('models.id'), nullable=False)
377
- portfolio_id = Column(UUID(as_uuid=True), ForeignKey('portfolios.id'))
404
+ model_id = Column(UUID(as_uuid=True), ForeignKey("models.id"), nullable=False)
405
+ portfolio_id = Column(UUID(as_uuid=True), ForeignKey("portfolios.id"))
378
406
 
379
407
  start_date = Column(DateTime, nullable=False)
380
408
  end_date = Column(DateTime, nullable=False)
@@ -414,14 +442,15 @@ class BacktestResult(Base):
414
442
 
415
443
  # Indexes
416
444
  __table_args__ = (
417
- Index('idx_backtest_model', 'model_id'),
418
- Index('idx_backtest_sharpe', 'sharpe_ratio'),
445
+ Index("idx_backtest_model", "model_id"),
446
+ Index("idx_backtest_sharpe", "sharpe_ratio"),
419
447
  )
420
448
 
421
449
 
422
450
  class Experiment(Base):
423
451
  """ML experiments tracking"""
424
- __tablename__ = 'experiments'
452
+
453
+ __tablename__ = "experiments"
425
454
 
426
455
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
427
456
  name = Column(String(100), nullable=False, index=True)
@@ -440,7 +469,7 @@ class Experiment(Base):
440
469
  test_metrics = Column(JSON)
441
470
 
442
471
  # Status
443
- status = Column(String(20), default='running') # running, completed, failed
472
+ status = Column(String(20), default="running") # running, completed, failed
444
473
 
445
474
  # Timing
446
475
  started_at = Column(DateTime, default=datetime.utcnow)
@@ -461,21 +490,22 @@ class Experiment(Base):
461
490
 
462
491
  # Indexes
463
492
  __table_args__ = (
464
- Index('idx_experiment_status', 'status'),
465
- Index('idx_experiment_created', 'created_at'),
493
+ Index("idx_experiment_status", "status"),
494
+ Index("idx_experiment_created", "created_at"),
466
495
  )
467
496
 
468
497
 
469
498
  class Model(Base):
470
499
  """ML models registry"""
471
- __tablename__ = 'models'
500
+
501
+ __tablename__ = "models"
472
502
 
473
503
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
474
504
  name = Column(String(100), nullable=False, index=True)
475
505
  version = Column(String(20), nullable=False)
476
506
 
477
507
  model_type = Column(String(50), nullable=False) # ensemble, lstm, transformer, etc.
478
- framework = Column(String(20), default='pytorch') # pytorch, tensorflow, sklearn
508
+ framework = Column(String(20), default="pytorch") # pytorch, tensorflow, sklearn
479
509
 
480
510
  # MLflow integration
481
511
  mlflow_model_uri = Column(String(500))
@@ -541,18 +571,19 @@ class Model(Base):
541
571
 
542
572
  # Constraints and indexes
543
573
  __table_args__ = (
544
- UniqueConstraint('name', 'version', name='unique_model_version'),
545
- Index('idx_model_status', 'status'),
546
- Index('idx_model_created', 'created_at'),
574
+ UniqueConstraint("name", "version", name="unique_model_version"),
575
+ Index("idx_model_status", "status"),
576
+ Index("idx_model_created", "created_at"),
547
577
  )
548
578
 
549
579
 
550
580
  class FeatureSet(Base):
551
581
  """Feature sets for models"""
552
- __tablename__ = 'feature_sets'
582
+
583
+ __tablename__ = "feature_sets"
553
584
 
554
585
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
555
- model_id = Column(UUID(as_uuid=True), ForeignKey('models.id'), nullable=False)
586
+ model_id = Column(UUID(as_uuid=True), ForeignKey("models.id"), nullable=False)
556
587
 
557
588
  name = Column(String(100), nullable=False)
558
589
  version = Column(String(20), nullable=False)
@@ -580,14 +611,15 @@ class FeatureSet(Base):
580
611
 
581
612
  # Constraints
582
613
  __table_args__ = (
583
- UniqueConstraint('model_id', 'name', 'version', name='unique_feature_set'),
584
- Index('idx_feature_set_model', 'model_id'),
614
+ UniqueConstraint("model_id", "name", "version", name="unique_feature_set"),
615
+ Index("idx_feature_set_model", "model_id"),
585
616
  )
586
617
 
587
618
 
588
619
  class DataVersion(Base):
589
620
  """Data versioning for DVC"""
590
- __tablename__ = 'data_versions'
621
+
622
+ __tablename__ = "data_versions"
591
623
 
592
624
  id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
593
625
 
@@ -618,27 +650,29 @@ class DataVersion(Base):
618
650
 
619
651
  # Constraints
620
652
  __table_args__ = (
621
- UniqueConstraint('dataset_name', 'version', name='unique_data_version'),
622
- Index('idx_data_version_created', 'created_at'),
653
+ UniqueConstraint("dataset_name", "version", name="unique_data_version"),
654
+ Index("idx_data_version_created", "created_at"),
623
655
  )
624
656
 
625
657
 
626
658
  # Database events and triggers
627
- @event.listens_for(User, 'before_insert')
659
+ @event.listens_for(User, "before_insert")
628
660
  def generate_api_key(mapper, connection, target):
629
661
  """Generate API key for new users"""
630
662
  if not target.api_key:
631
663
  import secrets
664
+
632
665
  target.api_key = secrets.token_urlsafe(32)
633
666
  target.api_key_created_at = datetime.utcnow()
634
667
 
635
668
 
636
- @event.listens_for(Portfolio, 'before_update')
669
+ @event.listens_for(Portfolio, "before_update")
637
670
  def update_portfolio_metrics(mapper, connection, target):
638
671
  """Update portfolio performance metrics"""
639
672
  if target.current_value and target.initial_capital:
640
- target.total_return = ((target.current_value - target.initial_capital) /
641
- target.initial_capital) * 100
673
+ target.total_return = (
674
+ (target.current_value - target.initial_capital) / target.initial_capital
675
+ ) * 100
642
676
 
643
677
 
644
678
  # Create indexes for better query performance
@@ -652,7 +686,6 @@ def create_indexes(engine):
652
686
  "CREATE INDEX IF NOT EXISTS idx_prediction_latest ON predictions(ticker, prediction_date DESC)",
653
687
  "CREATE INDEX IF NOT EXISTS idx_portfolio_performance ON portfolios(user_id, total_return DESC)",
654
688
  "CREATE INDEX IF NOT EXISTS idx_alert_priority ON alerts(user_id, is_read, severity, created_at DESC)",
655
-
656
689
  # Full text search indexes (PostgreSQL specific)
657
690
  "CREATE INDEX IF NOT EXISTS idx_politician_name_search ON politicians USING gin(to_tsvector('english', name))",
658
691
  "CREATE INDEX IF NOT EXISTS idx_stock_company_search ON stock_data USING gin(to_tsvector('english', company_name))",
@@ -664,4 +697,4 @@ def create_indexes(engine):
664
697
  conn.execute(text(index_sql))
665
698
  conn.commit()
666
699
  except Exception as e:
667
- print(f"Warning: Could not create index: {e}")
700
+ print(f"Warning: Could not create index: {e}")
@@ -1,16 +1,16 @@
1
1
  """Database session management"""
2
2
 
3
+ from contextlib import asynccontextmanager, contextmanager
3
4
  from typing import AsyncGenerator, Generator
4
- from contextlib import contextmanager, asynccontextmanager
5
5
 
6
6
  from sqlalchemy import create_engine
7
- from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
8
- from sqlalchemy.orm import sessionmaker, Session
7
+ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
8
+ from sqlalchemy.orm import Session, sessionmaker
9
9
  from sqlalchemy.pool import NullPool, StaticPool
10
10
 
11
11
  from mcli.ml.config import settings
12
- from .models import Base
13
12
 
13
+ from .models import Base
14
14
 
15
15
  # Synchronous database setup
16
16
  engine = create_engine(
@@ -125,6 +125,7 @@ def init_db() -> None:
125
125
 
126
126
  # Create additional indexes
127
127
  from .models import create_indexes
128
+
128
129
  create_indexes(engine)
129
130
 
130
131
 
@@ -197,4 +198,4 @@ async def bulk_update(model_class, data: list, key_field: str = "id") -> None:
197
198
  .where(getattr(model_class, key_field) == key_value)
198
199
  .values(**item)
199
200
  )
200
- await session.commit()
201
+ await session.commit()