lecrapaud 0.4.0__py3-none-any.whl → 0.4.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 lecrapaud might be problematic. Click here for more details.

Files changed (42) hide show
  1. lecrapaud/__init__.py +1 -0
  2. lecrapaud/api.py +277 -0
  3. lecrapaud/config.py +10 -0
  4. lecrapaud/db/__init__.py +1 -0
  5. lecrapaud/db/alembic/env.py +2 -2
  6. lecrapaud/db/alembic/versions/2025_05_31_1834-52b809a34371_make_nullablee.py +24 -12
  7. lecrapaud/db/alembic/versions/2025_06_17_1652-c45f5e49fa2c_make_fields_nullable.py +89 -0
  8. lecrapaud/db/alembic.ini +116 -0
  9. lecrapaud/db/models/__init__.py +10 -10
  10. lecrapaud/db/models/base.py +176 -1
  11. lecrapaud/db/models/dataset.py +25 -20
  12. lecrapaud/db/models/feature.py +5 -6
  13. lecrapaud/db/models/feature_selection.py +3 -4
  14. lecrapaud/db/models/feature_selection_rank.py +3 -4
  15. lecrapaud/db/models/model.py +3 -4
  16. lecrapaud/db/models/model_selection.py +15 -8
  17. lecrapaud/db/models/model_training.py +15 -7
  18. lecrapaud/db/models/score.py +9 -6
  19. lecrapaud/db/models/target.py +16 -8
  20. lecrapaud/db/session.py +68 -0
  21. lecrapaud/experiment.py +64 -0
  22. lecrapaud/feature_engineering.py +747 -1022
  23. lecrapaud/feature_selection.py +915 -998
  24. lecrapaud/integrations/openai_integration.py +225 -0
  25. lecrapaud/jobs/__init__.py +2 -2
  26. lecrapaud/jobs/config.py +1 -1
  27. lecrapaud/jobs/scheduler.py +1 -1
  28. lecrapaud/jobs/tasks.py +6 -6
  29. lecrapaud/model_selection.py +1060 -960
  30. lecrapaud/search_space.py +4 -0
  31. lecrapaud/utils.py +2 -2
  32. lecrapaud-0.4.2.dist-info/METADATA +177 -0
  33. {lecrapaud-0.4.0.dist-info → lecrapaud-0.4.2.dist-info}/RECORD +36 -35
  34. {lecrapaud-0.4.0.dist-info → lecrapaud-0.4.2.dist-info}/WHEEL +1 -1
  35. lecrapaud/db/crud.py +0 -179
  36. lecrapaud/db/services.py +0 -0
  37. lecrapaud/db/setup.py +0 -58
  38. lecrapaud/predictions.py +0 -292
  39. lecrapaud/training.py +0 -151
  40. lecrapaud-0.4.0.dist-info/METADATA +0 -103
  41. /lecrapaud/{directory_management.py → directories.py} +0 -0
  42. {lecrapaud-0.4.0.dist-info → lecrapaud-0.4.2.dist-info}/LICENSE +0 -0
lecrapaud/search_space.py CHANGED
@@ -48,6 +48,7 @@ from keras.activations import sigmoid
48
48
 
49
49
  # Search spaces
50
50
  from ray import tune
51
+ import pandas as pd
51
52
 
52
53
  # we cannot use tune.sample_from function to make conditionnal search space, because hyperopt and bayesian opt need a fixed search space
53
54
 
@@ -842,3 +843,6 @@ def get_models_idx(*model_names):
842
843
  i for i, model in enumerate(models) if model["model_name"] in model_names
843
844
  ]
844
845
  return matching_idx
846
+
847
+
848
+ all_models = ml_models + dl_recurrent_models
lecrapaud/utils.py CHANGED
@@ -10,8 +10,8 @@ import unicodedata
10
10
  import re
11
11
  import string
12
12
 
13
- from src.directory_management import logger_dir
14
- from src.config import LOGGING_LEVEL, PYTHON_ENV
13
+ from lecrapaud.directories import logger_dir
14
+ from lecrapaud.config import LOGGING_LEVEL, PYTHON_ENV
15
15
 
16
16
  _LOGGER_ALREADY_CONFIGURED = False
17
17
 
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.3
2
+ Name: lecrapaud
3
+ Version: 0.4.2
4
+ Summary: Framework for machine and deep learning, with regression, classification and time series analysis
5
+ License: Apache License
6
+ Author: Pierre H. Gallet
7
+ Requires-Python: ==3.12.*
8
+ Classifier: License :: Other/Proprietary License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Requires-Dist: backoff (>=2.2.1)
12
+ Requires-Dist: category-encoders (>=2.8.1)
13
+ Requires-Dist: celery (>=5.5.1)
14
+ Requires-Dist: curl-cffi (>=0.11.1)
15
+ Requires-Dist: deep-translator (>=1.11.4)
16
+ Requires-Dist: degiro-connector (>=3.0.26)
17
+ Requires-Dist: fake-useragent (>=2.1.0)
18
+ Requires-Dist: ftfy (>=6.3.1)
19
+ Requires-Dist: honeybadger (>=0.21)
20
+ Requires-Dist: joblib (>=1.4.2)
21
+ Requires-Dist: keras (>=3.9.0)
22
+ Requires-Dist: keras-tcn (>=3.1.2)
23
+ Requires-Dist: lightgbm (>=4.6.0)
24
+ Requires-Dist: matplotlib (>=3.10.1)
25
+ Requires-Dist: mlxtend (>=0.23.4)
26
+ Requires-Dist: numpy (>=2.1.3)
27
+ Requires-Dist: openai (>=1.86.0)
28
+ Requires-Dist: pandas (>=2.2.3)
29
+ Requires-Dist: pandas-market-calendars (>=4.6.1)
30
+ Requires-Dist: playwright (>=1.52.0)
31
+ Requires-Dist: pydantic (>=2.10.6)
32
+ Requires-Dist: python-dotenv (>=1.0.1)
33
+ Requires-Dist: pytz (>=2025.1)
34
+ Requires-Dist: ratelimit (>=2.2.1)
35
+ Requires-Dist: scikit-learn (>=1.6.1)
36
+ Requires-Dist: scipy (>=1.15.2)
37
+ Requires-Dist: seaborn (>=0.13.2)
38
+ Requires-Dist: sentence-transformers (>=3.4.1)
39
+ Requires-Dist: sqlalchemy (>=2.0.39)
40
+ Requires-Dist: tensorboardx (>=2.6.2.2)
41
+ Requires-Dist: tensorflow (>=2.19.0)
42
+ Requires-Dist: tf-keras (>=2.19.0)
43
+ Requires-Dist: tiktoken (>=0.9.0)
44
+ Requires-Dist: tqdm (>=4.67.1)
45
+ Requires-Dist: xgboost (>=3.0.0)
46
+ Requires-Dist: yahoo-fin (>=0.8.9.1)
47
+ Requires-Dist: yfinance (>=0.2.55)
48
+ Description-Content-Type: text/markdown
49
+
50
+ <div align="center">
51
+
52
+ <img src="https://s3.amazonaws.com/pix.iemoji.com/images/emoji/apple/ios-12/256/frog-face.png" width=120 alt="crapaud"/>
53
+
54
+ ## Welcome to LeCrapaud
55
+
56
+ **An all-in-one machine learning framework**
57
+
58
+ [![GitHub stars](https://img.shields.io/github/stars/pierregallet/lecrapaud.svg?style=flat&logo=github&colorB=blue&label=stars)](https://github.com/pierregallet/lecrapaud/stargazers)
59
+ [![PyPI version](https://badge.fury.io/py/lecrapaud.svg)](https://badge.fury.io/py/lecrapaud)
60
+ [![Python versions](https://img.shields.io/pypi/pyversions/lecrapaud.svg)](https://pypi.org/project/lecrapaud)
61
+ [![License](https://img.shields.io/github/license/pierregallet/lecrapaud.svg)](https://github.com/pierregallet/lecrapaud/blob/main/LICENSE)
62
+ [![codecov](https://codecov.io/gh/pierregallet/lecrapaud/branch/main/graph/badge.svg)](https://codecov.io/gh/pierregallet/lecrapaud)
63
+
64
+ </div>
65
+
66
+ ## 🚀 Introduction
67
+
68
+ LeCrapaud is a high-level Python library for end-to-end machine learning workflows on tabular data, with a focus on financial and stock datasets. It provides a simple API to handle feature engineering, model selection, training, and prediction, all in a reproducible and modular way.
69
+
70
+ ## ✨ Key Features
71
+
72
+ - 🧩 Modular pipeline: Feature engineering, preprocessing, selection, and modeling as independent steps
73
+ - 🤖 Automated model selection and hyperparameter optimization
74
+ - 📊 Easy integration with pandas DataFrames
75
+ - 🔬 Supports both regression and classification tasks
76
+ - 🛠️ Simple API for both full pipeline and step-by-step usage
77
+ - 📦 Ready for production and research workflows
78
+
79
+ ## ⚡ Quick Start
80
+
81
+
82
+ ### Install the package
83
+
84
+ ```sh
85
+ pip install lecrapaud
86
+ ```
87
+
88
+ ### How it works
89
+
90
+ This package provides a high-level API to manage experiments for feature engineering, model selection, and prediction on tabular data (e.g. stock data).
91
+
92
+ ### Typical workflow
93
+
94
+ ```python
95
+ from lecrapaud import LeCrapaud
96
+
97
+ # 1. Create the main app
98
+ app = LeCrapaud()
99
+
100
+ # 2. Define your experiment context (see your notebook or api.py for all options)
101
+ context = {
102
+ "data": your_dataframe,
103
+ "columns_drop": [...],
104
+ "columns_date": [...],
105
+ # ... other config options
106
+ }
107
+
108
+ # 3. Create an experiment
109
+ experiment = app.create_experiment(**context)
110
+
111
+ # 4. Run the full training pipeline
112
+ experiment.train(your_dataframe)
113
+
114
+ # 5. Make predictions on new data
115
+ predictions = experiment.predict(new_data)
116
+ ```
117
+
118
+ ### Modular usage
119
+
120
+ You can also use each step independently:
121
+
122
+ ```python
123
+ data_eng = experiment.feature_engineering(data)
124
+ train, val, test = experiment.preprocess_feature(data_eng)
125
+ features = experiment.feature_selection(train)
126
+ std_data, reshaped_data = experiment.preprocess_model(train, val, test)
127
+ experiment.model_selection(std_data, reshaped_data)
128
+ ```
129
+
130
+ ## 🤝 Contributing
131
+
132
+ ### Reminders for Github usage
133
+
134
+ 1. Creating Github repository
135
+
136
+ ```sh
137
+ $ brew install gh
138
+ $ gh auth login
139
+ $ gh repo create
140
+ ```
141
+
142
+ 2. Initializing git and first commit to distant repository
143
+
144
+ ```sh
145
+ $ git init
146
+ $ git add .
147
+ $ git commit -m 'first commit'
148
+ $ git remote add origin <YOUR_REPO_URL>
149
+ $ git push -u origin master
150
+ ```
151
+
152
+ 3. Use conventional commits
153
+ https://www.conventionalcommits.org/en/v1.0.0/#summary
154
+
155
+ 4. Create environment
156
+
157
+ ```sh
158
+ $ pip install virtualenv
159
+ $ python -m venv .venv
160
+ $ source .venv/bin/activate
161
+ ```
162
+
163
+ 5. Install dependencies
164
+
165
+ ```sh
166
+ $ make install
167
+ ```
168
+
169
+ 6. Deactivate virtualenv (if needed)
170
+
171
+ ```sh
172
+ $ deactivate
173
+ ```
174
+
175
+ ---
176
+
177
+ Pierre Gallet © 2025
@@ -1,8 +1,9 @@
1
- lecrapaud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- lecrapaud/config.py,sha256=887tTPkjK3Nt9wrduTmghmX_qKTFjMiZgy589flC-vw,496
3
- lecrapaud/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1
+ lecrapaud/__init__.py,sha256=oCxbtw_nk8rlOXbXbWo0RRMlsh6w-hTiZ6e5PRG_wp0,28
2
+ lecrapaud/api.py,sha256=3yAoHTJt1XtjCrLemwZnoY7UyTdsZo9a7-jgbkOnirc,9912
3
+ lecrapaud/config.py,sha256=Jf7kknumJ9NudVoLugOxqLqB7zTSl67IVV2VVWA0Pv4,1027
4
+ lecrapaud/db/__init__.py,sha256=82o9fMfaqKXPh2_rt44EzNRVZV1R4LScEnQYvj_TjK0,34
4
5
  lecrapaud/db/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
5
- lecrapaud/db/alembic/env.py,sha256=iJDgajC3RzQOiv0C-kpsC6d4AofhM2U0-m2de45rPWY,2150
6
+ lecrapaud/db/alembic/env.py,sha256=OwO56oeL7o3XQe2pnhMxK9C3Yeoz-ZCnGUSnXkNU-rg,2164
6
7
  lecrapaud/db/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
7
8
  lecrapaud/db/alembic/versions/2025_04_06_1738-7390745388e4_initial_setup.py,sha256=k-IPzyKK6Jk0Xf7Hu9awxnMw4bJOxDaKtEnesREvJ5Q,17069
8
9
  lecrapaud/db/alembic/versions/2025_04_06_1755-40cd8d3e798e_unique_constraint_for_data.py,sha256=6NvzMm3J7Lh8pUFoF8Ov4J1V8M9fBXAQV69BNB89QNw,841
@@ -15,34 +16,35 @@ lecrapaud/db/alembic/versions/2025_05_27_2047-6b6f2d38e9bc_double_instead_of_flo
15
16
  lecrapaud/db/alembic/versions/2025_05_31_1111-c175e4a36d68_generalise_stock_to_group.py,sha256=oezuATpCoIsWEuMNB4M19LIb6y_a3UHskFjf7nF_-gk,1312
16
17
  lecrapaud/db/alembic/versions/2025_05_31_1256-5681095bfc27_create_investment_run_and_portfolio_.py,sha256=6kdAkFkVQi7hJQx-B1YhA_og2HkGep1gHITXivMNZR4,2850
17
18
  lecrapaud/db/alembic/versions/2025_05_31_1806-339927587383_add_investment_run_id.py,sha256=AdN1DzPOgtMDQQFbM62URsv1IxbPUO1_kNzy1Yl1oIc,3346
18
- lecrapaud/db/alembic/versions/2025_05_31_1834-52b809a34371_make_nullablee.py,sha256=40luKBAdfTJxhSgzKogm3nPbo4xvJKJmIEKcoD9V7tk,1331
19
+ lecrapaud/db/alembic/versions/2025_05_31_1834-52b809a34371_make_nullablee.py,sha256=mnwDhWUFd-7FECHSn0_OGI93jxOeK4H2L4gp3ioqTDE,1234
19
20
  lecrapaud/db/alembic/versions/2025_05_31_1849-3b8550297e8e_change_date_to_datetime.py,sha256=d5swE95kdKovIBClS_tmTgNtN8epgMMz1X7DxPI17Lw,1356
20
21
  lecrapaud/db/alembic/versions/2025_05_31_1852-e6b8c95d8243_add_date_to_portfolio_history.py,sha256=veTx2DTbJDZ-wUhQTHJRA9lKam6To45jtRKT1UTX93I,829
21
22
  lecrapaud/db/alembic/versions/2025_06_10_1136-db8cdd83563a_addnewsandoptiontodata.py,sha256=V_Wjm-XMfMyG988R-3ii3-fzHP_tb2FtZmc4C6WkQOM,907
22
- lecrapaud/db/crud.py,sha256=4gbkqDlLiGioPfl0De3FDE2DD3pry2fMANoXKXDPckI,4778
23
- lecrapaud/db/models/__init__.py,sha256=eYPXbHmTdG3yOvkTJDNh3ms0Qo5ME7gwhfzp_3LzlLU,480
24
- lecrapaud/db/models/base.py,sha256=r-a6bBCgJ54FLyVW4IT-y-D8Y2dGYGNddCa8AAJaNHI,108
25
- lecrapaud/db/models/dataset.py,sha256=cUURxrD9ryA3BvERZAv1HThDb7rHNDxDhMvdHkRRboM,3705
26
- lecrapaud/db/models/feature.py,sha256=SnB4kzkKAlvGO89hONr-lT93-rRTQqsFAl5O-4I9KQM,1162
27
- lecrapaud/db/models/feature_selection.py,sha256=cw5-Ksl6FqBScNnWs3EZieX6EGlwblPyMHWPq8iy0i0,3268
28
- lecrapaud/db/models/feature_selection_rank.py,sha256=OBMoZ7LBc3vc1-O6V0w1bY5VaxYg9u42qbqZrZ8c3z4,2117
29
- lecrapaud/db/models/model.py,sha256=FhqbzHjVKQ_tQkUR6fqLfKrS7daksj5G2won-x3untI,1012
30
- lecrapaud/db/models/model_selection.py,sha256=kwhLmJSWOSyY4rBfrVhYWL43_kyjz8U4Pf922-83KZY,1738
31
- lecrapaud/db/models/model_training.py,sha256=igxoXJFzm3OR6pRxoJjS-JLFld4z3dnSb6Ri0DHw8aI,1579
32
- lecrapaud/db/models/score.py,sha256=vLoj3n5XhAcgXecxR1aUhZyyTEY75VmL3eaKXF_DhdQ,1722
33
- lecrapaud/db/models/target.py,sha256=J-2IuU8JWT0uxCcaAUxiY7nLegXfAM9Jq_83oaH-SgM,1594
34
- lecrapaud/db/services.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- lecrapaud/db/setup.py,sha256=35pEGb3jo5LFq0Fr29RoupzltPJTZm23jlqXbYisyLc,1747
36
- lecrapaud/directory_management.py,sha256=wrHmAJ-cBKb0GhJifxrb_RoLhZJX8xdkeirrWs7jQHk,791
37
- lecrapaud/feature_engineering.py,sha256=90ZCLYZiR92bnp0ze9KaPcP7tCuJUzgy1PBAeKTaUSg,39032
38
- lecrapaud/feature_selection.py,sha256=X741mvvOonW0NjdIriVGgBwDTRFxAJsUVcrsTL6wxk0,43329
39
- lecrapaud/jobs/__init__.py,sha256=9r8sii_z3ypGFxhkqgYLTsXMGhd0ZdhV3wpEyPEozas,280
40
- lecrapaud/jobs/config.py,sha256=mSVH41US6iZml5Sc4fr4Xx_RyiC8LB9idywqKdOhMl8,371
41
- lecrapaud/jobs/scheduler.py,sha256=E9oofuXuR1WtZPxSGSpWaIsM1aKgaan-K2xras-1weE,984
42
- lecrapaud/jobs/tasks.py,sha256=P6cuqM1q8WiD5lRc1HvZMJlMUOiR7thobia0op_VmZ0,1604
43
- lecrapaud/model_selection.py,sha256=7wl3aMMg1mSJxtMNUJXCGzRyCW76A202ZMzNmlxyCl8,55944
44
- lecrapaud/predictions.py,sha256=nQkaHXPtmK0HpO1pdvXR7yhCODRmgztd8xjlqDp9IW8,10719
45
- lecrapaud/search_space.py,sha256=XrTCPyl7by1wpqgWAPjmHaVIhL73yCnCaftEH7_a4IM,34056
23
+ lecrapaud/db/alembic/versions/2025_06_17_1652-c45f5e49fa2c_make_fields_nullable.py,sha256=0avBVj5WwNXZjCMuobqJFTtwMAlHNIWx5jsIpBR2lgs,2887
24
+ lecrapaud/db/alembic.ini,sha256=lQe8leIj1uOfXX5s2t-mmDPz3KRQYWX2nVBfneDLBew,3587
25
+ lecrapaud/db/models/__init__.py,sha256=oiOQitb8zEA7TK262zWLN6xnbZWYfg4eOaKVfAVyAFA,540
26
+ lecrapaud/db/models/base.py,sha256=zXI7biTA6-nzdTW8I71nGhHubkNLDFrQ5L1k9heOnuo,4889
27
+ lecrapaud/db/models/dataset.py,sha256=KnnsCThMvU1s7fqrhTmrn8eX6S776SrVd6eiqKNe2Xg,3705
28
+ lecrapaud/db/models/feature.py,sha256=-6K6zk8KHhdQHIuJ4PpXI6FJyw9nLmSlhlRjoglb5dE,1138
29
+ lecrapaud/db/models/feature_selection.py,sha256=mhlxu-aeYszLBqp7Z-QHTQI7P-ZXTeIja7fuX_BJsfw,3237
30
+ lecrapaud/db/models/feature_selection_rank.py,sha256=urPxiGwYNYMb-QU9ky2nX2oDlGoGiwzrNbHjeKYDTwM,2086
31
+ lecrapaud/db/models/model.py,sha256=tMUUdnp83pjp76Ypx7hORgEDux9kybG120_mtaJ0Ztc,981
32
+ lecrapaud/db/models/model_selection.py,sha256=Lj2WZBWvaVpJeDjdiAs8wvkoI-XrWv2IIjY34SetCBY,1773
33
+ lecrapaud/db/models/model_training.py,sha256=2xv9SOh8IUV1ROSsKlooAGanl9G8nBdmr7vaV4GAWtw,1618
34
+ lecrapaud/db/models/score.py,sha256=I6kA55ZQhReo9dA_JEgeRSqDoFKmYyL3l-zCffwsofs,1719
35
+ lecrapaud/db/models/target.py,sha256=scEtXVO3oysEvg9uwm_ncsS3-4o2A6z6XiDVGrg5WHE,1644
36
+ lecrapaud/db/session.py,sha256=TIk6ZgNZieKx3wmkt1vrHrU6i0Qwn6nrp4mzUrM1CK4,2131
37
+ lecrapaud/directories.py,sha256=wrHmAJ-cBKb0GhJifxrb_RoLhZJX8xdkeirrWs7jQHk,791
38
+ lecrapaud/experiment.py,sha256=ApsGtGaISYsQCdAGa1llzBslfODK-w1_zf44p6Es3Xs,1985
39
+ lecrapaud/feature_engineering.py,sha256=MEPW8-AgO3xnbwMHV3dC_gMtrBeKQhaCDrAicWgXX6w,30251
40
+ lecrapaud/feature_selection.py,sha256=RD016F9_r249VEAe5bLCpB4tHQSbhdMoXRFohkk3c5g,42429
41
+ lecrapaud/integrations/openai_integration.py,sha256=hHLF3fk5Bps8KNbNrEL3NUFa945jwClE6LrLpuMZOd4,7459
42
+ lecrapaud/jobs/__init__.py,sha256=ZkrsyTOR21c_wN7RY8jPhm8jCrL1oCEtTsf3VFIlQiE,292
43
+ lecrapaud/jobs/config.py,sha256=AmO0j3RFjx8H66dfKw_7vnshaOJb9Ox5BAZ9cwwLFMY,377
44
+ lecrapaud/jobs/scheduler.py,sha256=SiYWPxokpKnR8V6btLOO6gbK0PEjSRoeG0kCbQvYPf4,990
45
+ lecrapaud/jobs/tasks.py,sha256=evzhOHpgp6Gvoz__jUipi-_HSNny7bWgAauHv2Hpxyk,1640
46
+ lecrapaud/model_selection.py,sha256=y01yOK5oB9hdeEJkjjavDJvYAUCR3PS6FWRAN43uDzo,61322
47
+ lecrapaud/search_space.py,sha256=6kVXDSmvpTuLKTlqQkKIzrJOM2P7HpqRiO3PR37VrsM,34123
46
48
  lecrapaud/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
49
  lecrapaud/services/embedding_categorical.py,sha256=jPKl3GjJ8STk5u0ux9VHbUYq-XRuNULhMJuXdeJAePU,2593
48
50
  lecrapaud/services/indicators.py,sha256=1iDxCRzqAeBEwbazQOl_1LJnw_ceM7IiYYWkJbs14s4,9190
@@ -52,9 +54,8 @@ lecrapaud/speed_tests/test-gpu-resnet.ipynb,sha256=27Vu7nYwujYeh3fOxBNCnKJn3MXNP
52
54
  lecrapaud/speed_tests/test-gpu-transformers.ipynb,sha256=k6MBSs_Um1h4PykvE-LTBcdpbWLbIFST_xl_AFW2jgI,8444
53
55
  lecrapaud/speed_tests/tests.ipynb,sha256=RjI7LDHSsbadUkea_hT14sD7ivljtIQk4NB5McXJ1bE,3835
54
56
  lecrapaud/speed_tests/trash.py,sha256=E4zrrRyVqeNEumWg8rYKquR9VTIULN52eCRqjmv_s58,1647
55
- lecrapaud/training.py,sha256=NXkpyrkofoEHafTkuVs6o_D6c9SZxcFGqL85HZAuLCQ,5112
56
- lecrapaud/utils.py,sha256=X_kqmYaLxRA_uQLdEO1bRI_YeDAbqKEi1rLwTbWkH6U,8095
57
- lecrapaud-0.4.0.dist-info/LICENSE,sha256=MImCryu0AnqhJE_uAZD-PIDKXDKb8sT7v0i1NOYeHTM,11350
58
- lecrapaud-0.4.0.dist-info/METADATA,sha256=EjL3Sj2NMwjmzvhqyNM_tnS5Ii1boVOtPOcQG_bDt6I,2452
59
- lecrapaud-0.4.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
60
- lecrapaud-0.4.0.dist-info/RECORD,,
57
+ lecrapaud/utils.py,sha256=TMlEyU6aRhgiYRtdbvKrlq2t1L9Al5BXfQ3cPbeHlX8,8098
58
+ lecrapaud-0.4.2.dist-info/LICENSE,sha256=MImCryu0AnqhJE_uAZD-PIDKXDKb8sT7v0i1NOYeHTM,11350
59
+ lecrapaud-0.4.2.dist-info/METADATA,sha256=69vSPi3zCcGsLYIwWxHrNLHVIRz6Y9HMIXgqP0kDNmQ,5187
60
+ lecrapaud-0.4.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
61
+ lecrapaud-0.4.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.1
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
lecrapaud/db/crud.py DELETED
@@ -1,179 +0,0 @@
1
- from sqlalchemy import desc, asc
2
- from sqlalchemy.inspection import inspect
3
- from functools import wraps
4
- from sqlalchemy.orm.attributes import InstrumentedAttribute
5
- from sqlalchemy import or_, and_, delete
6
-
7
- from src.db.setup import get_db
8
-
9
-
10
- def with_db(func):
11
- """Decorator to allow passing an optional db session"""
12
-
13
- @wraps(func)
14
- def wrapper(*args, **kwargs):
15
- db = kwargs.pop("db", None)
16
- if db:
17
- return func(*args, db=db, **kwargs)
18
- with get_db() as db:
19
- return func(*args, db=db, **kwargs)
20
-
21
- return wrapper
22
-
23
-
24
- class CRUDMixin:
25
-
26
- @classmethod
27
- @with_db
28
- def create(cls, db, **kwargs):
29
- instance = cls(**kwargs)
30
- db.add(instance)
31
- db.commit()
32
- db.refresh(instance)
33
- return instance
34
-
35
- @classmethod
36
- @with_db
37
- def get(cls, id: int, db=None):
38
- return db.get(cls, id)
39
-
40
- @classmethod
41
- @with_db
42
- def find_by(cls, db=None, **kwargs):
43
- return db.query(cls).filter_by(**kwargs).first()
44
-
45
- @classmethod
46
- @with_db
47
- def get_all(
48
- cls, raw=False, db=None, limit: int = 100, order: str = "desc", **kwargs
49
- ):
50
- order_by_field = (
51
- desc(cls.created_at) if order == "desc" else asc(cls.created_at)
52
- )
53
-
54
- query = db.query(cls)
55
-
56
- # Apply filters from kwargs
57
- for key, value in kwargs.items():
58
- if hasattr(cls, key):
59
- query = query.filter(getattr(cls, key) == value)
60
-
61
- results = query.order_by(order_by_field).limit(limit).all()
62
-
63
- if raw:
64
- return [
65
- {
66
- column.name: getattr(row, column.name)
67
- for column in cls.__table__.columns
68
- }
69
- for row in results
70
- ]
71
-
72
- return results
73
-
74
- @classmethod
75
- @with_db
76
- def filter(cls, db=None, **kwargs):
77
- filters = []
78
-
79
- for key, value in kwargs.items():
80
- if "__" in key:
81
- field, op = key.split("__", 1)
82
- else:
83
- field, op = key, "eq"
84
-
85
- if not hasattr(cls, field):
86
- raise ValueError(f"{field} is not a valid field on {cls.__name__}")
87
-
88
- column: InstrumentedAttribute = getattr(cls, field)
89
-
90
- if op == "eq":
91
- filters.append(column == value)
92
- elif op == "in":
93
- filters.append(column.in_(value))
94
- elif op == "gt":
95
- filters.append(column > value)
96
- elif op == "lt":
97
- filters.append(column < value)
98
- elif op == "gte":
99
- filters.append(column >= value)
100
- elif op == "lte":
101
- filters.append(column <= value)
102
- else:
103
- raise ValueError(f"Unsupported operator: {op}")
104
-
105
- return db.query(cls).filter(and_(*filters)).all()
106
-
107
- @classmethod
108
- @with_db
109
- def update(cls, id: int, db=None, **kwargs):
110
- instance = db.get(cls, id)
111
- if not instance:
112
- return None
113
- for key, value in kwargs.items():
114
- setattr(instance, key, value)
115
- db.commit()
116
- db.refresh(instance)
117
- return instance
118
-
119
- @classmethod
120
- @with_db
121
- def upsert(cls, match_fields: list[str], db=None, **kwargs):
122
- """
123
- Upsert an instance of the model: update if found, else create.
124
-
125
- :param match_fields: list of field names to use for matching
126
- :param kwargs: all fields for creation or update
127
- """
128
- filters = [
129
- getattr(cls, field) == kwargs[field]
130
- for field in match_fields
131
- if field in kwargs
132
- ]
133
-
134
- instance = db.query(cls).filter(*filters).first()
135
-
136
- if instance:
137
- for key, value in kwargs.items():
138
- setattr(instance, key, value)
139
- else:
140
- instance = cls(**kwargs)
141
- db.add(instance)
142
-
143
- db.commit()
144
- db.refresh(instance)
145
- return instance
146
-
147
- @classmethod
148
- @with_db
149
- def delete(cls, id: int, db=None):
150
- instance = db.get(cls, id)
151
- if instance:
152
- db.delete(instance)
153
- db.commit()
154
- return True
155
- return False
156
-
157
- @classmethod
158
- @with_db
159
- def delete_all(cls, db=None, **kwargs):
160
- stmt = delete(cls)
161
-
162
- for key, value in kwargs.items():
163
- if hasattr(cls, key):
164
- stmt = stmt.where(getattr(cls, key) == value)
165
-
166
- db.execute(stmt)
167
- db.commit()
168
- return True
169
-
170
- @with_db
171
- def save(self, db=None):
172
- self = db.merge(self)
173
- db.add(self)
174
- db.commit()
175
- db.refresh(self)
176
- return self
177
-
178
- def to_json(self):
179
- return {c.key: getattr(self, c.key) for c in inspect(self).mapper.column_attrs}
lecrapaud/db/services.py DELETED
File without changes
lecrapaud/db/setup.py DELETED
@@ -1,58 +0,0 @@
1
- from sqlalchemy import create_engine, text, MetaData
2
- from sqlalchemy.orm import sessionmaker
3
- import os
4
- from contextlib import contextmanager
5
- from dotenv import load_dotenv
6
-
7
- load_dotenv()
8
-
9
- if os.getenv("PYTHON_ENV") == "Test":
10
- DB_USER = os.getenv("TEST_DB_USER", "root")
11
- DB_PASSWORD = os.getenv("TEST_DB_PASSWORD", "")
12
- DB_HOST = os.getenv("TEST_DB_HOST", "127.0.0.1")
13
- DB_PORT = os.getenv("TEST_DB_PORT", "3306")
14
- DB_NAME = os.getenv("TEST_DB_NAME", "test_stock_db")
15
- else:
16
- DB_USER = os.getenv("DB_USER", "root")
17
- DB_PASSWORD = os.getenv("DB_PASSWORD", "")
18
- DB_HOST = os.getenv("DB_HOST", "localhost")
19
- DB_PORT = os.getenv("DB_PORT", "3306")
20
- DB_NAME = os.getenv("DB_NAME", "stock_db")
21
-
22
- # Step 1: Connect to MySQL without a database
23
- root_engine = create_engine(
24
- f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/"
25
- )
26
-
27
- # Step 2: Create database if it doesn't exist
28
- with root_engine.connect() as conn:
29
- conn.execute(text(f"CREATE DATABASE IF NOT EXISTS {DB_NAME}"))
30
- conn.commit()
31
-
32
- # Step 3: Connect to the newly created database
33
- DATABASE_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
34
- engine = create_engine(DATABASE_URL, echo=False)
35
-
36
- # Step 4: Create session factory
37
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
38
-
39
- # Step 5: Create tables
40
- RESET_DB = False
41
- if RESET_DB:
42
- metadata = MetaData()
43
- metadata.reflect(bind=engine)
44
- metadata.drop_all(bind=engine)
45
- # Base.metadata.create_all(bind=engine)
46
-
47
-
48
- # Dependency to get a session instance
49
- @contextmanager
50
- def get_db():
51
- db = SessionLocal()
52
- try:
53
- yield db
54
- except Exception as e:
55
- db.rollback()
56
- raise Exception(e)
57
- finally:
58
- db.close()