ecodev-core 0.0.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 ecodev-core might be problematic. Click here for more details.
- ecodev_core/__init__.py +79 -0
- ecodev_core/app_activity.py +108 -0
- ecodev_core/app_rights.py +24 -0
- ecodev_core/app_user.py +92 -0
- ecodev_core/auth_configuration.py +22 -0
- ecodev_core/authentication.py +226 -0
- ecodev_core/check_dependencies.py +179 -0
- ecodev_core/custom_equal.py +27 -0
- ecodev_core/db_connection.py +68 -0
- ecodev_core/db_filters.py +142 -0
- ecodev_core/db_insertion.py +108 -0
- ecodev_core/db_retrieval.py +194 -0
- ecodev_core/enum_utils.py +21 -0
- ecodev_core/list_utils.py +65 -0
- ecodev_core/logger.py +106 -0
- ecodev_core/pandas_utils.py +30 -0
- ecodev_core/permissions.py +15 -0
- ecodev_core/pydantic_utils.py +52 -0
- ecodev_core/read_write.py +40 -0
- ecodev_core/safe_utils.py +197 -0
- ecodev_core-0.0.1.dist-info/LICENSE.md +11 -0
- ecodev_core-0.0.1.dist-info/METADATA +72 -0
- ecodev_core-0.0.1.dist-info/RECORD +24 -0
- ecodev_core-0.0.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unittest wrapper ensuring safe setUp / tearDown of all tests.
|
|
3
|
+
This boilerplate code is not to be touched under any circumstances.
|
|
4
|
+
"""
|
|
5
|
+
import contextlib
|
|
6
|
+
import shutil
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
from typing import Callable
|
|
10
|
+
from typing import List
|
|
11
|
+
from typing import Union
|
|
12
|
+
from unittest import TestCase
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from pydantic import Field
|
|
16
|
+
|
|
17
|
+
from ecodev_core.logger import log_critical
|
|
18
|
+
from ecodev_core.logger import logger_get
|
|
19
|
+
from ecodev_core.pydantic_utils import Frozen
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
log = logger_get(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SafeTestCase(TestCase):
|
|
26
|
+
"""
|
|
27
|
+
SafeTestCase makes sure that setUp / tearDown methods are always run when they should be.
|
|
28
|
+
This boilerplate code is not to be touched under any circumstances.
|
|
29
|
+
"""
|
|
30
|
+
files_created: List[Path]
|
|
31
|
+
directories_created: List[Path]
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def setUpClass(cls) -> None:
|
|
35
|
+
"""
|
|
36
|
+
Class set up, prompt class name and set files and folders to be suppressed at tearDownClass
|
|
37
|
+
"""
|
|
38
|
+
log.info(f'Running test module: {cls.__module__.upper()}')
|
|
39
|
+
super().setUpClass()
|
|
40
|
+
cls.directories_created = []
|
|
41
|
+
cls.files_created = []
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def tearDownClass(cls) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Safely suppress all files and directories used for this class
|
|
47
|
+
"""
|
|
48
|
+
log.info(f'Done running test module: {cls.__module__.upper()}')
|
|
49
|
+
cls.safe_delete(cls.directories_created, cls.files_created)
|
|
50
|
+
|
|
51
|
+
def setUp(self) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Test set up, prompt test name and set files and folders to be suppressed at tearDown
|
|
54
|
+
"""
|
|
55
|
+
super().setUp()
|
|
56
|
+
log.debug(f'Running test: {self._testMethodName.upper()}')
|
|
57
|
+
self.directories_created: List[Path] = []
|
|
58
|
+
self.files_created: List[Path] = []
|
|
59
|
+
|
|
60
|
+
def tearDown(self) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Safely suppress all files and directories used for this test
|
|
63
|
+
"""
|
|
64
|
+
log.debug(f'Done running test: {self._testMethodName.upper()}')
|
|
65
|
+
self.safe_delete(self.directories_created, self.files_created)
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def safe_delete(cls, directories_created: List[Path], files_created: List[Path]) -> None:
|
|
69
|
+
"""
|
|
70
|
+
Safely suppress all passed files_created and directories_created
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
directories_created: directories used for the test making the call
|
|
74
|
+
files_created: files_created used for the test making the call
|
|
75
|
+
"""
|
|
76
|
+
for directory in directories_created:
|
|
77
|
+
with contextlib.suppress(FileNotFoundError):
|
|
78
|
+
shutil.rmtree(directory)
|
|
79
|
+
for file_path in files_created:
|
|
80
|
+
file_path.unlink(missing_ok=True)
|
|
81
|
+
|
|
82
|
+
def run(self, result=None):
|
|
83
|
+
"""
|
|
84
|
+
Wrapper around unittest run
|
|
85
|
+
"""
|
|
86
|
+
test_method = getattr(self, self._testMethodName)
|
|
87
|
+
wrapped_test = self._cleanup_wrapper(test_method, KeyboardInterrupt)
|
|
88
|
+
setattr(self, self._testMethodName, wrapped_test)
|
|
89
|
+
self.setUp = self._cleanup_wrapper(self.setUp, BaseException)
|
|
90
|
+
|
|
91
|
+
return super().run(result)
|
|
92
|
+
|
|
93
|
+
def _cleanup_wrapper(self, method, exception):
|
|
94
|
+
"""
|
|
95
|
+
Boilerplate code for clean setup and teardown
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def _wrapped(*args, **kwargs):
|
|
99
|
+
try:
|
|
100
|
+
return method(*args, **kwargs)
|
|
101
|
+
except exception:
|
|
102
|
+
self.tearDown()
|
|
103
|
+
self.doCleanups()
|
|
104
|
+
raise
|
|
105
|
+
|
|
106
|
+
return _wrapped
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class SimpleReturn(Frozen):
|
|
110
|
+
"""
|
|
111
|
+
Simple output for routes not returning anything
|
|
112
|
+
"""
|
|
113
|
+
success: bool = Field(..., description=' True if the treatment went well.')
|
|
114
|
+
error: Union[str, None] = Field(..., description='the error that happened, if any.')
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def route_success(cls) -> 'SimpleReturn':
|
|
118
|
+
"""
|
|
119
|
+
Format DropDocumentReturn if the document was successfully dropped
|
|
120
|
+
"""
|
|
121
|
+
return SimpleReturn(success=True, error=None)
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def route_failure(cls, error: str) -> 'SimpleReturn':
|
|
125
|
+
"""
|
|
126
|
+
Format DropDocumentReturn if the document failed to be dropped
|
|
127
|
+
"""
|
|
128
|
+
return SimpleReturn(success=False, error=error)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def safe_clt(func):
|
|
132
|
+
"""
|
|
133
|
+
Safe execution of typer commands
|
|
134
|
+
"""
|
|
135
|
+
def inner_function(*args, **kwargs):
|
|
136
|
+
try:
|
|
137
|
+
func(*args, **kwargs)
|
|
138
|
+
return SimpleReturn.route_success()
|
|
139
|
+
except Exception as error:
|
|
140
|
+
log_critical(f'something wrong happened: {error}', log)
|
|
141
|
+
return SimpleReturn.route_failure(str(error))
|
|
142
|
+
return inner_function
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def stringify(x: Union[str, float]) -> Union[str, None]:
|
|
146
|
+
"""
|
|
147
|
+
Safe conversion of a (str, np.nan) value into a (str,None) one
|
|
148
|
+
"""
|
|
149
|
+
return _transformify(x, str)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def boolify(x: Union[Any]) -> Union[bool, None]:
|
|
153
|
+
"""
|
|
154
|
+
Safe conversion of a (str, np.nan) value into a (str,None) one
|
|
155
|
+
"""
|
|
156
|
+
return _transformify(x, _bool_check)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def intify(x: Union[str, float]) -> Union[int, None]:
|
|
160
|
+
"""
|
|
161
|
+
Safe conversion of a (int, np.nan) value into a (int,None) one
|
|
162
|
+
"""
|
|
163
|
+
return _transformify(x, int)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def floatify(x: Union[str, float]) -> Union[float, None]:
|
|
167
|
+
"""
|
|
168
|
+
Safe conversion of a (float, np.nan) value into a (float,None) one
|
|
169
|
+
"""
|
|
170
|
+
return _transformify(x, float)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _transformify(x: Union[Any, float], transformation: Callable) -> Union[Any, None]:
|
|
174
|
+
"""
|
|
175
|
+
Safe conversion of a (Any, np.nan) value into a (Any,None) one thanks to transformation
|
|
176
|
+
"""
|
|
177
|
+
if x is None or (isinstance(x, float) and np.isnan(x)):
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
return transformation(x)
|
|
182
|
+
|
|
183
|
+
except ValueError:
|
|
184
|
+
return None
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _bool_check(x: Union[Any, float]):
|
|
188
|
+
"""
|
|
189
|
+
Check if the passed element can be cast into a boolean, or the boolean value inferred.
|
|
190
|
+
"""
|
|
191
|
+
if isinstance(x, bool):
|
|
192
|
+
return x
|
|
193
|
+
|
|
194
|
+
if not isinstance(x, str) or x.lower() not in ['true', 'yes', 'false', 'no']:
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
return x.lower() in ['true', 'yes']
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Copyright 2024 Thomas EPELBAUM
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction,
|
|
4
|
+
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
5
|
+
subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
10
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
11
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ecodev-core
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Low level sqlmodel/fastapi/pydantic building blocks
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Thomas Epelbaum
|
|
7
|
+
Author-email: tomepel@gmail.com
|
|
8
|
+
Requires-Python: >=3.11,<4.0
|
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
|
+
Classifier: Environment :: Web Environment
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Framework :: Pydantic
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Information Technology
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
26
|
+
Classifier: Topic :: Database
|
|
27
|
+
Classifier: Topic :: Database :: Database Engines/Servers
|
|
28
|
+
Classifier: Topic :: Internet
|
|
29
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
30
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
31
|
+
Classifier: Topic :: Software Development
|
|
32
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
33
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
34
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
35
|
+
Classifier: Typing :: Typed
|
|
36
|
+
Requires-Dist: fastapi (>=0,<1)
|
|
37
|
+
Requires-Dist: httpx (>=0,<1)
|
|
38
|
+
Requires-Dist: numpy (>=1,<2)
|
|
39
|
+
Requires-Dist: pandas (>=2,<3)
|
|
40
|
+
Requires-Dist: passlib[bcyrypt] (>=1,<2)
|
|
41
|
+
Requires-Dist: pydantic[python-dotenv] (>=2,<3)
|
|
42
|
+
Requires-Dist: python-jose[cryptography] (>=3,<4)
|
|
43
|
+
Requires-Dist: sqladmin (==0.15.2)
|
|
44
|
+
Requires-Dist: sqlmodel (>=0,<1)
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
# ecodev-core
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions" target="_blank">
|
|
51
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/blob/main/badges/coverage.svg" alt="Coverage">
|
|
52
|
+
</a>
|
|
53
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions" target="_blank">
|
|
54
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/blob/main/badges/pylint.svg" alt="Publish">
|
|
55
|
+
</a>
|
|
56
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions/workflows/code-quality.yml/badge.svg" target="_blank">
|
|
57
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/actions/workflows/code-quality.yml/badge.svg" alt="Package version">
|
|
58
|
+
</a>
|
|
59
|
+
</p>
|
|
60
|
+
|
|
61
|
+
Low level ecoact generic code. Aimed at being published in open source with poetry
|
|
62
|
+
|
|
63
|
+
## Installation of this package
|
|
64
|
+
|
|
65
|
+
You are strongly encouraged to install this package via Docker.
|
|
66
|
+
|
|
67
|
+
Starting from a project with a Docker file:
|
|
68
|
+
* add the module ecodev-core in the `requirements.txt` file
|
|
69
|
+
* make sure the `.env` file includes all required fields (see `BaseSettings` and `AuthenticationConfiguration`)
|
|
70
|
+
* build the new version of the Docker container (typically `docker build --tag xxx .`)
|
|
71
|
+
* run it with docker compose (`dc up -d`).
|
|
72
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
ecodev_core/__init__.py,sha256=1DXQiiIgldhxRKg8d1SQsh5O1Ncgo2vz3mFBCPPzM_4,4128
|
|
2
|
+
ecodev_core/app_activity.py,sha256=_rU5uPfttHxXX5IaCuTA7K9We5w2qluJ3Xpf6i12HhY,3763
|
|
3
|
+
ecodev_core/app_rights.py,sha256=RZPdDtydFqc_nFj96huKAc56BS0qS6ScKv4Kghqd6lc,726
|
|
4
|
+
ecodev_core/app_user.py,sha256=qXvu0GOm2fAY_KxjkPEUIw7Rb9uxm2kvyFvcTTBQvEg,2949
|
|
5
|
+
ecodev_core/auth_configuration.py,sha256=qMaiv3F18cQiIT7QBML76FY4LP6XkmFy9t7a_bbBYQk,462
|
|
6
|
+
ecodev_core/authentication.py,sha256=x-lJMeZKOeP93NhqZbLJ-to9rgjW26S5qBOakeYzS_g,7635
|
|
7
|
+
ecodev_core/check_dependencies.py,sha256=aFn8GI4eBbuJT8RxsfhSSnlpNYYj_LPOH-tZF0EqfKQ,6917
|
|
8
|
+
ecodev_core/custom_equal.py,sha256=2gRn0qpyJ8-Kw9GQSueu0nLngLrRrwyMPlP6zqPac0U,899
|
|
9
|
+
ecodev_core/db_connection.py,sha256=Z5tvaLL2SmScwft38X1yliAxgQPGY8IRRa2-XNyzQTY,1732
|
|
10
|
+
ecodev_core/db_filters.py,sha256=T_5JVF27UEu7sC6NOm7-W3_Y0GLfbWQO_EeTXcD2cv8,5041
|
|
11
|
+
ecodev_core/db_insertion.py,sha256=hwDr_S0PhMrOqA9eAnye9-s15yFmVsbz8XI_tZ9WCnU,3629
|
|
12
|
+
ecodev_core/db_retrieval.py,sha256=fYSD0q2jYxfZzxWVrg-M3uPOnfAgvxf3VZd1pg9Pf5M,7413
|
|
13
|
+
ecodev_core/enum_utils.py,sha256=BkQ4YQ97tXBYmMcQiSIi0mbioD5CgVU79myg1BBAXuA,556
|
|
14
|
+
ecodev_core/list_utils.py,sha256=z6jdXR7dRL1djaWWlTKmUfSVH60VHUwlM1FC3clO100,2364
|
|
15
|
+
ecodev_core/logger.py,sha256=AWGGNZz12Ql0JDq1wCJQxwxK2syiczEBftmuJkjbAPw,3149
|
|
16
|
+
ecodev_core/pandas_utils.py,sha256=fSB1cAOHwgC0loum-LVd_9u5sSf2CXZGotHo56Q5bcE,1079
|
|
17
|
+
ecodev_core/permissions.py,sha256=dMaRQyjrF8Y51gkbkFvFsGVdzQGLZtA72IQ7REYamxg,320
|
|
18
|
+
ecodev_core/pydantic_utils.py,sha256=KKZ9Dhek-QX64Cvl_SNWUj1DwwGIEnybYkO4joHIGXA,1006
|
|
19
|
+
ecodev_core/read_write.py,sha256=auJ5bBJTVGkLRkiP_vZxVCX64B0Y-9qpsaDhovHmbas,996
|
|
20
|
+
ecodev_core/safe_utils.py,sha256=uTHzLnKBoV_MiFsI65X-WYmgzLpIBH5Cio80KSLd6wg,5933
|
|
21
|
+
ecodev_core-0.0.1.dist-info/LICENSE.md,sha256=rZtBt3Nj4cv7-tvFHCundioUJ00zCya33G-jnuR9fNw,1063
|
|
22
|
+
ecodev_core-0.0.1.dist-info/METADATA,sha256=TolpNhlTmUzJjl5_ZtLYCfI2nJQVWItRhQ01KZQJmg4,3074
|
|
23
|
+
ecodev_core-0.0.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
24
|
+
ecodev_core-0.0.1.dist-info/RECORD,,
|