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.

@@ -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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.8.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any