Safe helpers¶
Low level helpers related to safe code execution
SafeTestCase
¶
In recent years, two test frameworks see the most use - unittest: the ancestor 😋 - pytest: the wannabe replacer 😋
For starting a new project, people usually advocate to use pytest.
But we start python a long time ago and went with unittest at the time. It never failed us, and this is why unnitest is used at EcoAct.
One recurring complain about unittest is the additionnal boilerplate code you need to make it work as pytest. This is true up to a certain extent true, but we
developed SafeTestCase
to centralized this boilerplate code. By replacing unnitest TestCase
with our SafeTestCase
, we hope to avoid you the boilerplate.
SafeTestCase
has two important attributes:
directories_created
: a list to which you can append directories meant to be used in one test and erased at the end of it.files_created
: a list to which you can append files meant to be used in one test and erased at the end of it.
In addition, you get out of the box these kind of logs (we plug on our logger)
Logs embedded with SafeTestCase
We hope you'll find SafeTestCase
as convenient as it is for us 😊.
SimpleReturn
¶
Usually the return of all our POST routes, inspired from the maybe monad.
Standard pattern in C#, and especially in rust. You could alo find it in python in the result library.
Its code is quite simple and hopefully enlightening.
from ecodev_core.pydantic_utils import Frozen
from pydantic import Field
from typing import Union
class SimpleReturn(Frozen):
"""
Simple output for routes not returning anything
"""
success: bool = Field(..., description=' True if the treatment went well.')
error: Union[str, None] = Field(..., description='the error that happened, if any.')
@classmethod
def route_success(cls) -> 'SimpleReturn':
"""
Format DropDocumentReturn if the document was successfully dropped
"""
return SimpleReturn(success=True, error=None)
@classmethod
def route_failure(cls, error: str) -> 'SimpleReturn':
"""
Format DropDocumentReturn if the document failed to be dropped
"""
return SimpleReturn(success=False, error=error)
stringify
¶
Safe conversion of a (str, np.nan) value into a (str,None) one
# test stringify behaviour
self.assertEqual(stringify(3), '3')
self.assertEqual(stringify(np.nan), None)
self.assertEqual(stringify('toto'), 'toto')
self.assertEqual(stringify('3'), '3')
boolify
¶
Safe conversion of a (str, np.nan) value into a (bool,None) one. By convention, Yes/yes/No/no are mapped to True/True/False/False
.
# test boolify behaviour
self.assertEqual(boolify('true'), True)
self.assertEqual(boolify('yes'), True)
self.assertEqual(boolify('True'), True)
self.assertEqual(boolify('Yes'), True)
self.assertEqual(boolify('false'), False)
self.assertEqual(boolify('no'), False)
self.assertEqual(boolify('False'), False)
self.assertEqual(boolify('No'), False)
self.assertEqual(boolify(np.nan), None)
self.assertEqual(boolify(True), True)
self.assertEqual(boolify(False), False)
self.assertEqual(boolify('toto'), None)
self.assertEqual(boolify(3), None)
self.assertEqual(boolify(None), None)
intify
¶
Safe conversion of a (int, np.nan) value into a (int,None) one
# test intify behaviour
self.assertEqual(intify(3), 3)
self.assertEqual(intify(np.nan), None)
self.assertEqual(intify('toto'), None)
self.assertEqual(intify('3'), 3)
floatify
¶
Safe conversion of a (float, np.nan) value into a (float,None) one
# test floatify behaviour
self.assertEqual(floatify(3), 3.0)
self.assertEqual(floatify(np.nan), None)
self.assertEqual(floatify('toto'), None)
self.assertEqual(floatify('3.0'), 3.0)
safe_clt
¶
A method wrapper to return a SimpleReturn
corresponding to success/failure execution of that said method.
Simple illustration
@safe_clt
def safe_divide(a: int, b: int):
"""
Safe test divide for testing purposes.
"""
return a / b
# Test that safe wrapper is working as intended.
self.assertEqual(safe_divide(1, 2), SimpleReturn(success=True, error=None))
self.assertEqual(safe_divide(1, 0), SimpleReturn(success=False, error='division by zero'))