lecrapaud 0.4.2__py3-none-any.whl → 0.5.0__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 lecrapaud might be problematic. Click here for more details.
- lecrapaud/config.py +15 -12
- lecrapaud/db/alembic/env.py +7 -2
- lecrapaud/db/alembic/versions/2025_06_20_1924-1edada319fd7_initial_setup.py +214 -0
- lecrapaud/db/alembic.ini +1 -1
- lecrapaud/db/models/base.py +28 -0
- lecrapaud/db/models/dataset.py +5 -6
- lecrapaud/db/models/feature.py +4 -3
- lecrapaud/db/models/feature_selection.py +11 -8
- lecrapaud/db/models/feature_selection_rank.py +4 -3
- lecrapaud/db/models/model.py +0 -1
- lecrapaud/db/models/model_selection.py +9 -4
- lecrapaud/db/models/model_training.py +2 -3
- lecrapaud/db/models/score.py +5 -13
- lecrapaud/db/models/target.py +2 -3
- lecrapaud/db/session.py +37 -17
- lecrapaud-0.5.0.dist-info/METADATA +263 -0
- lecrapaud-0.5.0.dist-info/RECORD +46 -0
- lecrapaud/db/alembic/versions/2025_04_06_1738-7390745388e4_initial_setup.py +0 -295
- lecrapaud/db/alembic/versions/2025_04_06_1755-40cd8d3e798e_unique_constraint_for_data.py +0 -30
- lecrapaud/db/alembic/versions/2025_05_23_1724-2360941fa0bd_longer_string.py +0 -52
- lecrapaud/db/alembic/versions/2025_05_27_1159-b96396dcfaff_add_env_to_trading_tables.py +0 -34
- lecrapaud/db/alembic/versions/2025_05_27_1337-40cbfc215f7c_fix_nb_character_on_portfolio.py +0 -39
- lecrapaud/db/alembic/versions/2025_05_27_1526-3de994115317_to_datetime.py +0 -36
- lecrapaud/db/alembic/versions/2025_05_27_2003-25c227c684f8_add_fees_to_transactions.py +0 -30
- lecrapaud/db/alembic/versions/2025_05_27_2047-6b6f2d38e9bc_double_instead_of_float.py +0 -132
- lecrapaud/db/alembic/versions/2025_05_31_1111-c175e4a36d68_generalise_stock_to_group.py +0 -36
- lecrapaud/db/alembic/versions/2025_05_31_1256-5681095bfc27_create_investment_run_and_portfolio_.py +0 -62
- lecrapaud/db/alembic/versions/2025_05_31_1806-339927587383_add_investment_run_id.py +0 -107
- lecrapaud/db/alembic/versions/2025_05_31_1834-52b809a34371_make_nullablee.py +0 -50
- lecrapaud/db/alembic/versions/2025_05_31_1849-3b8550297e8e_change_date_to_datetime.py +0 -44
- lecrapaud/db/alembic/versions/2025_05_31_1852-e6b8c95d8243_add_date_to_portfolio_history.py +0 -30
- lecrapaud/db/alembic/versions/2025_06_10_1136-db8cdd83563a_addnewsandoptiontodata.py +0 -32
- lecrapaud/db/alembic/versions/2025_06_17_1652-c45f5e49fa2c_make_fields_nullable.py +0 -89
- lecrapaud-0.4.2.dist-info/METADATA +0 -177
- lecrapaud-0.4.2.dist-info/RECORD +0 -61
- {lecrapaud-0.4.2.dist-info → lecrapaud-0.5.0.dist-info}/LICENSE +0 -0
- {lecrapaud-0.4.2.dist-info → lecrapaud-0.5.0.dist-info}/WHEEL +0 -0
lecrapaud/config.py
CHANGED
|
@@ -5,22 +5,25 @@ load_dotenv(override=False)
|
|
|
5
5
|
|
|
6
6
|
PYTHON_ENV = os.getenv("PYTHON_ENV")
|
|
7
7
|
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379")
|
|
8
|
-
EMAIL = os.getenv("EMAIL")
|
|
9
8
|
DATASET_ID = os.getenv("DATASET_ID")
|
|
10
|
-
RECEIVER_EMAIL = os.getenv("RECEIVER_EMAIL")
|
|
11
|
-
USERNAME = os.getenv("USERNAME")
|
|
12
|
-
FRAISE = os.getenv("FRAISE")
|
|
13
|
-
FA2 = os.getenv("2FA")
|
|
14
|
-
INT = os.getenv("INT")
|
|
15
9
|
LOGGING_LEVEL = os.getenv("LOGGING_LEVEL", "INFO")
|
|
16
|
-
ALPHA_VENTAGE_API_KEY = os.getenv("ALPHA_VENTAGE_API_KEY")
|
|
17
10
|
|
|
18
|
-
DB_USER =
|
|
11
|
+
DB_USER = (
|
|
12
|
+
os.getenv("TEST_DB_USER") if PYTHON_ENV == "Test" else os.getenv("DB_USER", None)
|
|
13
|
+
)
|
|
19
14
|
DB_PASSWORD = (
|
|
20
|
-
os.getenv("TEST_DB_PASSWORD")
|
|
15
|
+
os.getenv("TEST_DB_PASSWORD")
|
|
16
|
+
if PYTHON_ENV == "Test"
|
|
17
|
+
else os.getenv("DB_PASSWORD", None)
|
|
18
|
+
)
|
|
19
|
+
DB_HOST = (
|
|
20
|
+
os.getenv("TEST_DB_HOST") if PYTHON_ENV == "Test" else os.getenv("DB_HOST", None)
|
|
21
|
+
)
|
|
22
|
+
DB_PORT = (
|
|
23
|
+
os.getenv("TEST_DB_PORT") if PYTHON_ENV == "Test" else os.getenv("DB_PORT", None)
|
|
24
|
+
)
|
|
25
|
+
DB_NAME = (
|
|
26
|
+
os.getenv("TEST_DB_NAME") if PYTHON_ENV == "Test" else os.getenv("DB_NAME", None)
|
|
21
27
|
)
|
|
22
|
-
DB_HOST = os.getenv("TEST_DB_HOST") if PYTHON_ENV == "Test" else os.getenv("DB_HOST")
|
|
23
|
-
DB_PORT = os.getenv("TEST_DB_PORT") if PYTHON_ENV == "Test" else os.getenv("DB_PORT")
|
|
24
|
-
DB_NAME = os.getenv("TEST_DB_NAME") if PYTHON_ENV == "Test" else os.getenv("DB_NAME")
|
|
25
28
|
DB_URI = os.getenv("DB_URI", None)
|
|
26
29
|
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
lecrapaud/db/alembic/env.py
CHANGED
|
@@ -5,6 +5,7 @@ from sqlalchemy import pool
|
|
|
5
5
|
|
|
6
6
|
from alembic import context
|
|
7
7
|
from lecrapaud.db.session import DATABASE_URL
|
|
8
|
+
from lecrapaud.db.models.base import Base
|
|
8
9
|
|
|
9
10
|
# this is the Alembic Config object, which provides
|
|
10
11
|
# access to the values within the .ini file in use.
|
|
@@ -18,7 +19,6 @@ if config.config_file_name is not None:
|
|
|
18
19
|
|
|
19
20
|
# add your model's MetaData object here
|
|
20
21
|
# for 'autogenerate' support
|
|
21
|
-
from lecrapaud.db.models.base import Base
|
|
22
22
|
|
|
23
23
|
target_metadata = Base.metadata
|
|
24
24
|
|
|
@@ -46,6 +46,7 @@ def run_migrations_offline() -> None:
|
|
|
46
46
|
target_metadata=target_metadata,
|
|
47
47
|
literal_binds=True,
|
|
48
48
|
dialect_opts={"paramstyle": "named"},
|
|
49
|
+
version_table="lecrapaud_alembic_version",
|
|
49
50
|
)
|
|
50
51
|
|
|
51
52
|
with context.begin_transaction():
|
|
@@ -66,7 +67,11 @@ def run_migrations_online() -> None:
|
|
|
66
67
|
)
|
|
67
68
|
|
|
68
69
|
with connectable.connect() as connection:
|
|
69
|
-
context.configure(
|
|
70
|
+
context.configure(
|
|
71
|
+
connection=connection,
|
|
72
|
+
target_metadata=target_metadata,
|
|
73
|
+
version_table="lecrapaud_alembic_version",
|
|
74
|
+
)
|
|
70
75
|
|
|
71
76
|
with context.begin_transaction():
|
|
72
77
|
context.run_migrations()
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""initial_setup
|
|
2
|
+
|
|
3
|
+
Revision ID: 1edada319fd7
|
|
4
|
+
Revises:
|
|
5
|
+
Create Date: 2025-06-20 19:24:25.033055
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = '1edada319fd7'
|
|
16
|
+
down_revision: Union[str, None] = None
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
23
|
+
op.create_table('lecrapaud_datasets',
|
|
24
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
25
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
26
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
27
|
+
sa.Column('name', sa.String(length=50), nullable=False),
|
|
28
|
+
sa.Column('path', sa.String(length=255), nullable=True),
|
|
29
|
+
sa.Column('type', sa.String(length=50), nullable=False),
|
|
30
|
+
sa.Column('size', sa.Integer(), nullable=False),
|
|
31
|
+
sa.Column('train_size', sa.Integer(), nullable=True),
|
|
32
|
+
sa.Column('val_size', sa.Integer(), nullable=True),
|
|
33
|
+
sa.Column('test_size', sa.Integer(), nullable=True),
|
|
34
|
+
sa.Column('corr_threshold', sa.Float(), nullable=False),
|
|
35
|
+
sa.Column('max_features', sa.Integer(), nullable=False),
|
|
36
|
+
sa.Column('percentile', sa.Float(), nullable=False),
|
|
37
|
+
sa.Column('number_of_groups', sa.Integer(), nullable=True),
|
|
38
|
+
sa.Column('list_of_groups', sa.JSON(), nullable=True),
|
|
39
|
+
sa.Column('start_date', sa.DateTime(), nullable=True),
|
|
40
|
+
sa.Column('end_date', sa.DateTime(), nullable=True),
|
|
41
|
+
sa.Column('train_start_date', sa.DateTime(), nullable=True),
|
|
42
|
+
sa.Column('train_end_date', sa.DateTime(), nullable=True),
|
|
43
|
+
sa.Column('val_start_date', sa.DateTime(), nullable=True),
|
|
44
|
+
sa.Column('val_end_date', sa.DateTime(), nullable=True),
|
|
45
|
+
sa.Column('test_start_date', sa.DateTime(), nullable=True),
|
|
46
|
+
sa.Column('test_end_date', sa.DateTime(), nullable=True),
|
|
47
|
+
sa.PrimaryKeyConstraint('id'),
|
|
48
|
+
sa.UniqueConstraint('name', name='uq_datasets_composite')
|
|
49
|
+
)
|
|
50
|
+
op.create_index(op.f('ix_lecrapaud_datasets_id'), 'lecrapaud_datasets', ['id'], unique=False)
|
|
51
|
+
op.create_table('lecrapaud_features',
|
|
52
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
53
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
54
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
55
|
+
sa.Column('name', sa.String(length=50), nullable=False),
|
|
56
|
+
sa.Column('type', sa.String(length=50), nullable=True),
|
|
57
|
+
sa.PrimaryKeyConstraint('id'),
|
|
58
|
+
sa.UniqueConstraint('name')
|
|
59
|
+
)
|
|
60
|
+
op.create_index(op.f('ix_lecrapaud_features_id'), 'lecrapaud_features', ['id'], unique=False)
|
|
61
|
+
op.create_table('lecrapaud_models',
|
|
62
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
63
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
64
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
65
|
+
sa.Column('name', sa.String(length=50), nullable=False),
|
|
66
|
+
sa.Column('type', sa.String(length=50), nullable=False),
|
|
67
|
+
sa.PrimaryKeyConstraint('id'),
|
|
68
|
+
sa.UniqueConstraint('name', 'type', name='uq_model_composite')
|
|
69
|
+
)
|
|
70
|
+
op.create_index(op.f('ix_lecrapaud_models_id'), 'lecrapaud_models', ['id'], unique=False)
|
|
71
|
+
op.create_table('lecrapaud_targets',
|
|
72
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
73
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
74
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
75
|
+
sa.Column('name', sa.String(length=50), nullable=False),
|
|
76
|
+
sa.Column('type', sa.String(length=50), nullable=False),
|
|
77
|
+
sa.Column('description', sa.String(length=255), nullable=True),
|
|
78
|
+
sa.PrimaryKeyConstraint('id'),
|
|
79
|
+
sa.UniqueConstraint('name', 'type', name='uq_target_composite')
|
|
80
|
+
)
|
|
81
|
+
op.create_index(op.f('ix_lecrapaud_targets_id'), 'lecrapaud_targets', ['id'], unique=False)
|
|
82
|
+
op.create_table('lecrapaud_dataset_target_association',
|
|
83
|
+
sa.Column('dataset_id', sa.BigInteger(), nullable=False),
|
|
84
|
+
sa.Column('target_id', sa.BigInteger(), nullable=False),
|
|
85
|
+
sa.ForeignKeyConstraint(['dataset_id'], ['lecrapaud_datasets.id'], ondelete='CASCADE'),
|
|
86
|
+
sa.ForeignKeyConstraint(['target_id'], ['lecrapaud_targets.id'], ondelete='CASCADE'),
|
|
87
|
+
sa.PrimaryKeyConstraint('dataset_id', 'target_id')
|
|
88
|
+
)
|
|
89
|
+
op.create_table('lecrapaud_feature_selections',
|
|
90
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
91
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
92
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
93
|
+
sa.Column('training_time', sa.Integer(), nullable=True),
|
|
94
|
+
sa.Column('best_features_path', sa.String(length=255), nullable=True),
|
|
95
|
+
sa.Column('dataset_id', sa.BigInteger(), nullable=False),
|
|
96
|
+
sa.Column('target_id', sa.BigInteger(), nullable=False),
|
|
97
|
+
sa.ForeignKeyConstraint(['dataset_id'], ['lecrapaud_datasets.id'], ondelete='CASCADE'),
|
|
98
|
+
sa.ForeignKeyConstraint(['target_id'], ['lecrapaud_targets.id'], ondelete='CASCADE'),
|
|
99
|
+
sa.PrimaryKeyConstraint('id'),
|
|
100
|
+
sa.UniqueConstraint('dataset_id', 'target_id', name='uq_feature_selection_composite')
|
|
101
|
+
)
|
|
102
|
+
op.create_index(op.f('ix_lecrapaud_feature_selections_id'), 'lecrapaud_feature_selections', ['id'], unique=False)
|
|
103
|
+
op.create_table('lecrapaud_model_selections',
|
|
104
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
105
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
106
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
107
|
+
sa.Column('best_model_params', sa.JSON(), nullable=True),
|
|
108
|
+
sa.Column('best_model_path', sa.String(length=255), nullable=True),
|
|
109
|
+
sa.Column('best_model_id', sa.BigInteger(), nullable=True),
|
|
110
|
+
sa.Column('target_id', sa.BigInteger(), nullable=False),
|
|
111
|
+
sa.Column('dataset_id', sa.BigInteger(), nullable=False),
|
|
112
|
+
sa.ForeignKeyConstraint(['best_model_id'], ['lecrapaud_models.id'], ondelete='CASCADE'),
|
|
113
|
+
sa.ForeignKeyConstraint(['dataset_id'], ['lecrapaud_datasets.id'], ondelete='CASCADE'),
|
|
114
|
+
sa.ForeignKeyConstraint(['target_id'], ['lecrapaud_targets.id'], ondelete='CASCADE'),
|
|
115
|
+
sa.PrimaryKeyConstraint('id'),
|
|
116
|
+
sa.UniqueConstraint('target_id', 'dataset_id', name='uq_model_selection_composite')
|
|
117
|
+
)
|
|
118
|
+
op.create_index(op.f('ix_lecrapaud_model_selections_id'), 'lecrapaud_model_selections', ['id'], unique=False)
|
|
119
|
+
op.create_table('lecrapaud_feature_selection_association',
|
|
120
|
+
sa.Column('feature_selection_id', sa.BigInteger(), nullable=False),
|
|
121
|
+
sa.Column('feature_id', sa.BigInteger(), nullable=False),
|
|
122
|
+
sa.ForeignKeyConstraint(['feature_id'], ['lecrapaud_features.id'], ondelete='CASCADE'),
|
|
123
|
+
sa.ForeignKeyConstraint(['feature_selection_id'], ['lecrapaud_feature_selections.id'], ondelete='CASCADE'),
|
|
124
|
+
sa.PrimaryKeyConstraint('feature_selection_id', 'feature_id')
|
|
125
|
+
)
|
|
126
|
+
op.create_table('lecrapaud_feature_selection_ranks',
|
|
127
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
128
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
129
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
130
|
+
sa.Column('score', sa.Float(), nullable=True),
|
|
131
|
+
sa.Column('pvalue', sa.Float(), nullable=True),
|
|
132
|
+
sa.Column('support', sa.Integer(), nullable=True),
|
|
133
|
+
sa.Column('rank', sa.Integer(), nullable=True),
|
|
134
|
+
sa.Column('method', sa.String(length=50), nullable=True),
|
|
135
|
+
sa.Column('training_time', sa.Integer(), nullable=True),
|
|
136
|
+
sa.Column('feature_id', sa.BigInteger(), nullable=True),
|
|
137
|
+
sa.Column('feature_selection_id', sa.BigInteger(), nullable=True),
|
|
138
|
+
sa.ForeignKeyConstraint(['feature_id'], ['lecrapaud_features.id'], ondelete='CASCADE'),
|
|
139
|
+
sa.ForeignKeyConstraint(['feature_selection_id'], ['lecrapaud_feature_selections.id'], ondelete='CASCADE'),
|
|
140
|
+
sa.PrimaryKeyConstraint('id'),
|
|
141
|
+
sa.UniqueConstraint('feature_id', 'feature_selection_id', 'method', name='uq_feature_selection_rank_composite')
|
|
142
|
+
)
|
|
143
|
+
op.create_index(op.f('ix_lecrapaud_feature_selection_ranks_id'), 'lecrapaud_feature_selection_ranks', ['id'], unique=False)
|
|
144
|
+
op.create_table('lecrapaud_model_trainings',
|
|
145
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
146
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
147
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
148
|
+
sa.Column('best_params', sa.JSON(), nullable=True),
|
|
149
|
+
sa.Column('model_path', sa.String(length=255), nullable=True),
|
|
150
|
+
sa.Column('training_time', sa.Integer(), nullable=True),
|
|
151
|
+
sa.Column('model_id', sa.BigInteger(), nullable=False),
|
|
152
|
+
sa.Column('model_selection_id', sa.BigInteger(), nullable=False),
|
|
153
|
+
sa.ForeignKeyConstraint(['model_id'], ['lecrapaud_models.id'], ),
|
|
154
|
+
sa.ForeignKeyConstraint(['model_selection_id'], ['lecrapaud_model_selections.id'], ondelete='CASCADE'),
|
|
155
|
+
sa.PrimaryKeyConstraint('id'),
|
|
156
|
+
sa.UniqueConstraint('model_id', 'model_selection_id', name='uq_model_training_composite')
|
|
157
|
+
)
|
|
158
|
+
op.create_index(op.f('ix_lecrapaud_model_trainings_id'), 'lecrapaud_model_trainings', ['id'], unique=False)
|
|
159
|
+
op.create_table('lecrapaud_scores',
|
|
160
|
+
sa.Column('id', sa.BigInteger(), autoincrement=True, nullable=False),
|
|
161
|
+
sa.Column('created_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
162
|
+
sa.Column('updated_at', sa.TIMESTAMP(timezone=True), server_default=sa.text('now()'), nullable=False),
|
|
163
|
+
sa.Column('type', sa.String(length=50), nullable=False),
|
|
164
|
+
sa.Column('training_time', sa.Integer(), nullable=True),
|
|
165
|
+
sa.Column('eval_data_std', sa.Float(), nullable=True),
|
|
166
|
+
sa.Column('rmse', sa.Float(), nullable=True),
|
|
167
|
+
sa.Column('rmse_std_ratio', sa.Float(), nullable=True),
|
|
168
|
+
sa.Column('mae', sa.Float(), nullable=True),
|
|
169
|
+
sa.Column('mape', sa.Float(), nullable=True),
|
|
170
|
+
sa.Column('mam', sa.Float(), nullable=True),
|
|
171
|
+
sa.Column('mad', sa.Float(), nullable=True),
|
|
172
|
+
sa.Column('mae_mam_ratio', sa.Float(), nullable=True),
|
|
173
|
+
sa.Column('mae_mad_ratio', sa.Float(), nullable=True),
|
|
174
|
+
sa.Column('r2', sa.Float(), nullable=True),
|
|
175
|
+
sa.Column('logloss', sa.Float(), nullable=True),
|
|
176
|
+
sa.Column('accuracy', sa.Float(), nullable=True),
|
|
177
|
+
sa.Column('precision', sa.Float(), nullable=True),
|
|
178
|
+
sa.Column('recall', sa.Float(), nullable=True),
|
|
179
|
+
sa.Column('f1', sa.Float(), nullable=True),
|
|
180
|
+
sa.Column('roc_auc', sa.Float(), nullable=True),
|
|
181
|
+
sa.Column('threshold', sa.Float(), nullable=True),
|
|
182
|
+
sa.Column('precision_at_threshold', sa.Float(), nullable=True),
|
|
183
|
+
sa.Column('recall_at_threshold', sa.Float(), nullable=True),
|
|
184
|
+
sa.Column('model_training_id', sa.BigInteger(), nullable=False),
|
|
185
|
+
sa.ForeignKeyConstraint(['model_training_id'], ['lecrapaud_model_trainings.id'], ondelete='CASCADE'),
|
|
186
|
+
sa.PrimaryKeyConstraint('id')
|
|
187
|
+
)
|
|
188
|
+
op.create_index(op.f('ix_lecrapaud_scores_id'), 'lecrapaud_scores', ['id'], unique=False)
|
|
189
|
+
# ### end Alembic commands ###
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def downgrade() -> None:
|
|
193
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
194
|
+
op.drop_index(op.f('ix_lecrapaud_scores_id'), table_name='lecrapaud_scores')
|
|
195
|
+
op.drop_table('lecrapaud_scores')
|
|
196
|
+
op.drop_index(op.f('ix_lecrapaud_model_trainings_id'), table_name='lecrapaud_model_trainings')
|
|
197
|
+
op.drop_table('lecrapaud_model_trainings')
|
|
198
|
+
op.drop_index(op.f('ix_lecrapaud_feature_selection_ranks_id'), table_name='lecrapaud_feature_selection_ranks')
|
|
199
|
+
op.drop_table('lecrapaud_feature_selection_ranks')
|
|
200
|
+
op.drop_table('lecrapaud_feature_selection_association')
|
|
201
|
+
op.drop_index(op.f('ix_lecrapaud_model_selections_id'), table_name='lecrapaud_model_selections')
|
|
202
|
+
op.drop_table('lecrapaud_model_selections')
|
|
203
|
+
op.drop_index(op.f('ix_lecrapaud_feature_selections_id'), table_name='lecrapaud_feature_selections')
|
|
204
|
+
op.drop_table('lecrapaud_feature_selections')
|
|
205
|
+
op.drop_table('lecrapaud_dataset_target_association')
|
|
206
|
+
op.drop_index(op.f('ix_lecrapaud_targets_id'), table_name='lecrapaud_targets')
|
|
207
|
+
op.drop_table('lecrapaud_targets')
|
|
208
|
+
op.drop_index(op.f('ix_lecrapaud_models_id'), table_name='lecrapaud_models')
|
|
209
|
+
op.drop_table('lecrapaud_models')
|
|
210
|
+
op.drop_index(op.f('ix_lecrapaud_features_id'), table_name='lecrapaud_features')
|
|
211
|
+
op.drop_table('lecrapaud_features')
|
|
212
|
+
op.drop_index(op.f('ix_lecrapaud_datasets_id'), table_name='lecrapaud_datasets')
|
|
213
|
+
op.drop_table('lecrapaud_datasets')
|
|
214
|
+
# ### end Alembic commands ###
|
lecrapaud/db/alembic.ini
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[alembic]
|
|
4
4
|
# path to migration scripts
|
|
5
|
-
script_location = lecrapaud
|
|
5
|
+
script_location = lecrapaud/db/alembic
|
|
6
6
|
|
|
7
7
|
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
|
8
8
|
# Uncomment the line below if you want the files to be prepended with date and time
|
lecrapaud/db/models/base.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""Base SQLAlchemy model with CRUD operations."""
|
|
2
2
|
|
|
3
3
|
from functools import wraps
|
|
4
|
+
import re
|
|
4
5
|
|
|
5
6
|
from sqlalchemy.orm import DeclarativeBase
|
|
6
7
|
from sqlalchemy import desc, asc, and_, delete
|
|
7
8
|
from sqlalchemy.inspection import inspect
|
|
8
9
|
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
9
10
|
from lecrapaud.db.session import get_db
|
|
11
|
+
from sqlalchemy.ext.declarative import declared_attr
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def with_db(func):
|
|
@@ -23,8 +25,34 @@ def with_db(func):
|
|
|
23
25
|
return wrapper
|
|
24
26
|
|
|
25
27
|
|
|
28
|
+
# Utility functions
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def camel_to_snake(name):
|
|
32
|
+
s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name)
|
|
33
|
+
s2 = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1)
|
|
34
|
+
return s2.lower()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def pluralize(name):
|
|
38
|
+
return name if name.endswith("s") else name + "s"
|
|
39
|
+
|
|
40
|
+
|
|
26
41
|
# declarative base class
|
|
27
42
|
class Base(DeclarativeBase):
|
|
43
|
+
@declared_attr
|
|
44
|
+
def __tablename__(cls):
|
|
45
|
+
# If the model sets __tablename__, use it (with prefix if not present)
|
|
46
|
+
if "__tablename__" in cls.__dict__:
|
|
47
|
+
base_name = cls.__dict__["__tablename__"]
|
|
48
|
+
if not base_name.startswith("lecrapaud_"):
|
|
49
|
+
return f"lecrapaud_{base_name}"
|
|
50
|
+
return base_name
|
|
51
|
+
# Otherwise, generate from class name
|
|
52
|
+
snake = camel_to_snake(cls.__name__)
|
|
53
|
+
plural = pluralize(snake)
|
|
54
|
+
return f"lecrapaud_{plural}"
|
|
55
|
+
|
|
28
56
|
@classmethod
|
|
29
57
|
@with_db
|
|
30
58
|
def create(cls, db, **kwargs):
|
lecrapaud/db/models/dataset.py
CHANGED
|
@@ -21,26 +21,25 @@ from lecrapaud.db.session import get_db
|
|
|
21
21
|
from lecrapaud.db.models.base import Base
|
|
22
22
|
|
|
23
23
|
# jointures
|
|
24
|
-
|
|
25
|
-
"
|
|
24
|
+
lecrapaud_dataset_target_association = Table(
|
|
25
|
+
"lecrapaud_dataset_target_association",
|
|
26
26
|
Base.metadata,
|
|
27
27
|
Column(
|
|
28
28
|
"dataset_id",
|
|
29
29
|
BigInteger,
|
|
30
|
-
ForeignKey("
|
|
30
|
+
ForeignKey("lecrapaud_datasets.id", ondelete="CASCADE"),
|
|
31
31
|
primary_key=True,
|
|
32
32
|
),
|
|
33
33
|
Column(
|
|
34
34
|
"target_id",
|
|
35
35
|
BigInteger,
|
|
36
|
-
ForeignKey("
|
|
36
|
+
ForeignKey("lecrapaud_targets.id", ondelete="CASCADE"),
|
|
37
37
|
primary_key=True,
|
|
38
38
|
),
|
|
39
39
|
)
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class Dataset(Base):
|
|
43
|
-
__tablename__ = "datasets"
|
|
44
43
|
|
|
45
44
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
46
45
|
created_at = Column(
|
|
@@ -87,7 +86,7 @@ class Dataset(Base):
|
|
|
87
86
|
)
|
|
88
87
|
targets = relationship(
|
|
89
88
|
"Target",
|
|
90
|
-
secondary=
|
|
89
|
+
secondary=lecrapaud_dataset_target_association,
|
|
91
90
|
back_populates="datasets",
|
|
92
91
|
lazy="selectin",
|
|
93
92
|
)
|
lecrapaud/db/models/feature.py
CHANGED
|
@@ -18,11 +18,12 @@ from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
|
|
|
18
18
|
|
|
19
19
|
from lecrapaud.db.session import get_db
|
|
20
20
|
from lecrapaud.db.models.base import Base
|
|
21
|
-
from lecrapaud.db.models.feature_selection import
|
|
21
|
+
from lecrapaud.db.models.feature_selection import (
|
|
22
|
+
lecrapaud_feature_selection_association,
|
|
23
|
+
)
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class Feature(Base):
|
|
25
|
-
__tablename__ = "features"
|
|
26
27
|
|
|
27
28
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
28
29
|
created_at = Column(
|
|
@@ -39,7 +40,7 @@ class Feature(Base):
|
|
|
39
40
|
|
|
40
41
|
feature_selections = relationship(
|
|
41
42
|
"FeatureSelection",
|
|
42
|
-
secondary=
|
|
43
|
+
secondary=lecrapaud_feature_selection_association,
|
|
43
44
|
back_populates="features",
|
|
44
45
|
lazy="selectin",
|
|
45
46
|
)
|
|
@@ -28,26 +28,25 @@ from lecrapaud.db.session import get_db
|
|
|
28
28
|
from lecrapaud.db.models.base import Base, with_db
|
|
29
29
|
|
|
30
30
|
# jointures
|
|
31
|
-
|
|
32
|
-
"
|
|
31
|
+
lecrapaud_feature_selection_association = Table(
|
|
32
|
+
"lecrapaud_feature_selection_association",
|
|
33
33
|
Base.metadata,
|
|
34
34
|
Column(
|
|
35
35
|
"feature_selection_id",
|
|
36
36
|
BigInteger,
|
|
37
|
-
ForeignKey("
|
|
37
|
+
ForeignKey("lecrapaud_feature_selections.id", ondelete="CASCADE"),
|
|
38
38
|
primary_key=True,
|
|
39
39
|
),
|
|
40
40
|
Column(
|
|
41
41
|
"feature_id",
|
|
42
42
|
BigInteger,
|
|
43
|
-
ForeignKey("
|
|
43
|
+
ForeignKey("lecrapaud_features.id", ondelete="CASCADE"),
|
|
44
44
|
primary_key=True,
|
|
45
45
|
),
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
class FeatureSelection(Base):
|
|
50
|
-
__tablename__ = "feature_selections"
|
|
51
50
|
|
|
52
51
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
53
52
|
created_at = Column(
|
|
@@ -62,10 +61,14 @@ class FeatureSelection(Base):
|
|
|
62
61
|
training_time = Column(Integer)
|
|
63
62
|
best_features_path = Column(String(255))
|
|
64
63
|
dataset_id = Column(
|
|
65
|
-
BigInteger,
|
|
64
|
+
BigInteger,
|
|
65
|
+
ForeignKey("lecrapaud_datasets.id", ondelete="CASCADE"),
|
|
66
|
+
nullable=False,
|
|
66
67
|
)
|
|
67
68
|
target_id = Column(
|
|
68
|
-
BigInteger,
|
|
69
|
+
BigInteger,
|
|
70
|
+
ForeignKey("lecrapaud_targets.id", ondelete="CASCADE"),
|
|
71
|
+
nullable=False,
|
|
69
72
|
)
|
|
70
73
|
|
|
71
74
|
dataset = relationship(
|
|
@@ -82,7 +85,7 @@ class FeatureSelection(Base):
|
|
|
82
85
|
)
|
|
83
86
|
features = relationship(
|
|
84
87
|
"Feature",
|
|
85
|
-
secondary=
|
|
88
|
+
secondary=lecrapaud_feature_selection_association,
|
|
86
89
|
back_populates="feature_selections",
|
|
87
90
|
lazy="selectin",
|
|
88
91
|
)
|
|
@@ -23,7 +23,6 @@ from lecrapaud.db.models.base import Base, with_db
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class FeatureSelectionRank(Base):
|
|
26
|
-
__tablename__ = "feature_selection_ranks"
|
|
27
26
|
|
|
28
27
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
29
28
|
created_at = Column(
|
|
@@ -41,9 +40,11 @@ class FeatureSelectionRank(Base):
|
|
|
41
40
|
rank = Column(Integer)
|
|
42
41
|
method = Column(String(50))
|
|
43
42
|
training_time = Column(Integer)
|
|
44
|
-
feature_id = Column(
|
|
43
|
+
feature_id = Column(
|
|
44
|
+
BigInteger, ForeignKey("lecrapaud_features.id", ondelete="CASCADE")
|
|
45
|
+
)
|
|
45
46
|
feature_selection_id = Column(
|
|
46
|
-
BigInteger, ForeignKey("
|
|
47
|
+
BigInteger, ForeignKey("lecrapaud_feature_selections.id", ondelete="CASCADE")
|
|
47
48
|
)
|
|
48
49
|
|
|
49
50
|
feature = relationship("Feature", lazy="selectin")
|
lecrapaud/db/models/model.py
CHANGED
|
@@ -22,7 +22,6 @@ from lecrapaud.db.models.base import Base
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class ModelSelection(Base):
|
|
25
|
-
__tablename__ = "model_selections"
|
|
26
25
|
|
|
27
26
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
28
27
|
created_at = Column(
|
|
@@ -36,12 +35,18 @@ class ModelSelection(Base):
|
|
|
36
35
|
)
|
|
37
36
|
best_model_params = Column(JSON)
|
|
38
37
|
best_model_path = Column(String(255))
|
|
39
|
-
best_model_id = Column(
|
|
38
|
+
best_model_id = Column(
|
|
39
|
+
BigInteger, ForeignKey("lecrapaud_models.id", ondelete="CASCADE")
|
|
40
|
+
)
|
|
40
41
|
target_id = Column(
|
|
41
|
-
BigInteger,
|
|
42
|
+
BigInteger,
|
|
43
|
+
ForeignKey("lecrapaud_targets.id", ondelete="CASCADE"),
|
|
44
|
+
nullable=False,
|
|
42
45
|
)
|
|
43
46
|
dataset_id = Column(
|
|
44
|
-
BigInteger,
|
|
47
|
+
BigInteger,
|
|
48
|
+
ForeignKey("lecrapaud_datasets.id", ondelete="CASCADE"),
|
|
49
|
+
nullable=False,
|
|
45
50
|
)
|
|
46
51
|
|
|
47
52
|
best_model = relationship("Model", lazy="selectin")
|
|
@@ -22,7 +22,6 @@ from lecrapaud.db.models.base import Base
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class ModelTraining(Base):
|
|
25
|
-
__tablename__ = "model_trainings"
|
|
26
25
|
|
|
27
26
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
28
27
|
created_at = Column(
|
|
@@ -37,10 +36,10 @@ class ModelTraining(Base):
|
|
|
37
36
|
best_params = Column(JSON)
|
|
38
37
|
model_path = Column(String(255))
|
|
39
38
|
training_time = Column(Integer)
|
|
40
|
-
model_id = Column(BigInteger, ForeignKey("
|
|
39
|
+
model_id = Column(BigInteger, ForeignKey("lecrapaud_models.id"), nullable=False)
|
|
41
40
|
model_selection_id = Column(
|
|
42
41
|
BigInteger,
|
|
43
|
-
ForeignKey("
|
|
42
|
+
ForeignKey("lecrapaud_model_selections.id", ondelete="CASCADE"),
|
|
44
43
|
nullable=False,
|
|
45
44
|
)
|
|
46
45
|
|
lecrapaud/db/models/score.py
CHANGED
|
@@ -2,27 +2,17 @@ from sqlalchemy import (
|
|
|
2
2
|
Column,
|
|
3
3
|
Integer,
|
|
4
4
|
String,
|
|
5
|
-
DateTime,
|
|
6
|
-
Date,
|
|
7
5
|
Float,
|
|
8
|
-
JSON,
|
|
9
|
-
Table,
|
|
10
6
|
ForeignKey,
|
|
11
7
|
BigInteger,
|
|
12
|
-
Index,
|
|
13
8
|
TIMESTAMP,
|
|
14
9
|
)
|
|
15
|
-
from sqlalchemy import
|
|
16
|
-
|
|
17
|
-
from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
|
|
18
|
-
|
|
19
|
-
from lecrapaud.db.session import get_db
|
|
10
|
+
from sqlalchemy import func
|
|
11
|
+
from sqlalchemy.orm import relationship
|
|
20
12
|
from lecrapaud.db.models.base import Base
|
|
21
13
|
|
|
22
14
|
|
|
23
15
|
class Score(Base):
|
|
24
|
-
__tablename__ = "scores"
|
|
25
|
-
|
|
26
16
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
27
17
|
created_at = Column(
|
|
28
18
|
TIMESTAMP(timezone=True), server_default=func.now(), nullable=False
|
|
@@ -57,7 +47,9 @@ class Score(Base):
|
|
|
57
47
|
precision_at_threshold = Column(Float)
|
|
58
48
|
recall_at_threshold = Column(Float)
|
|
59
49
|
model_training_id = Column(
|
|
60
|
-
BigInteger,
|
|
50
|
+
BigInteger,
|
|
51
|
+
ForeignKey("lecrapaud_model_trainings.id", ondelete="CASCADE"),
|
|
52
|
+
nullable=False,
|
|
61
53
|
)
|
|
62
54
|
|
|
63
55
|
model_trainings = relationship(
|
lecrapaud/db/models/target.py
CHANGED
|
@@ -19,11 +19,10 @@ from sqlalchemy.orm import relationship, Mapped, mapped_column, DeclarativeBase
|
|
|
19
19
|
|
|
20
20
|
from lecrapaud.db.session import get_db
|
|
21
21
|
from lecrapaud.db.models.base import Base
|
|
22
|
-
from lecrapaud.db.models.dataset import
|
|
22
|
+
from lecrapaud.db.models.dataset import lecrapaud_dataset_target_association
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class Target(Base):
|
|
26
|
-
__tablename__ = "targets"
|
|
27
26
|
|
|
28
27
|
id = Column(BigInteger, primary_key=True, index=True, autoincrement=True)
|
|
29
28
|
created_at = Column(
|
|
@@ -41,7 +40,7 @@ class Target(Base):
|
|
|
41
40
|
|
|
42
41
|
datasets = relationship(
|
|
43
42
|
"Dataset",
|
|
44
|
-
secondary=
|
|
43
|
+
secondary=lecrapaud_dataset_target_association,
|
|
45
44
|
back_populates="targets",
|
|
46
45
|
lazy="selectin",
|
|
47
46
|
)
|