From b1ad6023c05556fb1029d7fd05b41eb0307cded0 Mon Sep 17 00:00:00 2001 From: dhondta Date: Tue, 7 May 2024 23:35:43 +0200 Subject: [PATCH] Applied minor improvements --- docs/pages/helpers.md | 5 ++ src/tinyscript/VERSION.txt | 2 +- src/tinyscript/features/timing.py | 1 - src/tinyscript/helpers/data/types/common.py | 68 +++++++++++++-------- src/tinyscript/helpers/timeout.py | 7 +-- tests/test_features_timing.py | 1 - tests/test_helpers_data_types.py | 9 +++ tests/test_helpers_timeout.py | 2 +- tests/test_preimports_code.py | 8 +-- 9 files changed, 65 insertions(+), 38 deletions(-) diff --git a/docs/pages/helpers.md b/docs/pages/helpers.md index 354b14d..45b3a48 100644 --- a/docs/pages/helpers.md +++ b/docs/pages/helpers.md @@ -334,6 +334,7 @@ Tinyscript provides some type checking functions, for common data: `ts.is_file` | dummy shortcut to `os.path.isfile` `ts.is_filemode` | simple file mode check (for Linux permissions) `ts.is_filetype` | regex-based check for file's type (relying on [`python-magic`](https://pypi.org/project/python-magic/)) +`ts.is_float` / `ts.is_pos_float` / `ts.is_neg_float` | float (positive / negative) `ts.is_hex` | hexadecimal string (case insensitive) `ts.is_in_path` | whether the target path is in the PATH environment variable `ts.is_int` / `ts.is_int_range` / `ts.is_pos_int` / `ts.is_neg_int` / `ts.is_prime` | integer (within range / positive / negative / prime) @@ -436,8 +437,12 @@ While adding arguments to the parser (relying on `argparse`), Tinyscript provide `ts.ints` | `list(int)` | list of integers `ts.int_range` | single integer within range (second bound included!) `ts.ints_range` | list of integers within range (second bound included!) +`ts.neg_float` / `negative_float` | `float` | single negative float +`ts.neg_floats` / `negative_floats` | `list(float)` | list of negative floats `ts.neg_int` / `negative_int` | `int` | single negative integer `ts.neg_ints` / `negative_ints` | `list(int)` | list of negative integers +`ts.pos_float` / `positive_float` | `float` | single positive float +`ts.pos_floats` / `positive_floats` | `list(float)` | list of positive floats `ts.pos_int` / `positive_int` | `int` | single positive integer `ts.pos_ints` / `positive_ints` | `list(int)` | list of positive integers `ts.regular_expression` | `str` | string that can be parsed as a regular expression diff --git a/src/tinyscript/VERSION.txt b/src/tinyscript/VERSION.txt index 8973180..1781c6f 100644 --- a/src/tinyscript/VERSION.txt +++ b/src/tinyscript/VERSION.txt @@ -1 +1 @@ -1.30.9 +1.30.10 diff --git a/src/tinyscript/features/timing.py b/src/tinyscript/features/timing.py index ac22e91..e0f936f 100644 --- a/src/tinyscript/features/timing.py +++ b/src/tinyscript/features/timing.py @@ -9,7 +9,6 @@ from .loglib import logger from ..helpers.constants import WINDOWS -from ..helpers.timeout import TimeoutError __all__ = ["set_time_items"] diff --git a/src/tinyscript/helpers/data/types/common.py b/src/tinyscript/helpers/data/types/common.py index 632622e..45fdecd 100644 --- a/src/tinyscript/helpers/data/types/common.py +++ b/src/tinyscript/helpers/data/types/common.py @@ -12,16 +12,19 @@ # various object type check functions -__all__ += ["is_bool", "is_dict", "is_int", "is_int_range", "is_list", "is_neg_int", "is_percentage", "is_pos_int", - "is_prime"] +__all__ += ["is_bool", "is_dict", "is_float", "is_int", "is_int_range", "is_list", "is_neg_float", "is_neg_int", + "is_percentage", "is_pos_float", "is_pos_int", "is_prime"] is_bool = lambda b: isinstance(b, bool) is_dict = lambda d: isinstance(d, dict) +is_float = lambda f: isinstance(f, float) is_int = lambda i: isinstance(i, int) is_int_range = lambda i, i1, i2=None: all(is_int(x) for x in [i, i1, i2 or 0]) and i in (range(i1+1) if i2 is None \ else range(i1, i2+1)) is_list = lambda l: isinstance(l, (list, set, tuple)) +is_neg_float = lambda f, zero=False: is_float(f) and (f <= 0. if zero else f < 0.) is_neg_int = lambda i, zero=False: is_int(i) and (i <= 0 if zero else i < 0) is_percentage = lambda f: isinstance(f, (int, float)) and 0. <= float(f) <= 1. +is_pos_float = lambda f, zero=False: is_float(f) and (f >= 0. if zero else f > 0.) is_pos_int = lambda i, zero=True: is_int(i) and (i >= 0 if zero else i > 0) is_prime = lambda i: __prime_number(i) @@ -43,29 +46,44 @@ # -------------------- DATA FORMAT ARGUMENT TYPES -------------------- -__all__ += ["int_range", "neg_int", "negative_int", "pos_int", "positive_int", "ints", "ints_range", "neg_ints", - "negative_ints", "pos_ints", "positive_ints", "prime_number", "values_list"] - - -def __ints(l, check_func=lambda x: False, idescr=None, shouldbe=None, **kwargs): - """ Parses a comma-separated list of ints. """ - l = _str2list(l) - msg = "{} {}integer{}".format(["Bad list of", "Not a"][len(l) == 1], "" if idescr is None else idescr + " ", - ["s", ""][len(l) == 1]) - if shouldbe is not None: - msg += " (should be %s)" % shouldbe - if not all(check_func(_, **kwargs) for _ in l): - raise ValueError(msg) - return l -ints = lambda l: __ints(l, is_int) -int_range = lambda i, i1, i2=None: __ints(i, is_int_range, "valid", "in range [%d,%d]" % \ - (0 if i2 is None else i1, i1 if i2 is None else i2), i1=i1, i2=i2)[0] -negative_int = neg_int = lambda i, zero=False: __ints(i, is_neg_int, "negative", zero=zero)[0] -positive_int = pos_int = lambda i, zero=True: __ints(i, is_pos_int, "positive", zero=zero)[0] -ints_range = lambda l, i1, i2=None: __ints(l, is_int_range, "valid", "in range [%d,%d]" % \ - (0 if i2 is None else i1, i1 if i2 is None else i2), i1=i1, i2=i2) -negative_ints = neg_ints = lambda l, zero=False: __ints(l, is_neg_int, "negative", zero=zero) -positive_ints = pos_ints = lambda l, zero=True: __ints(l, is_pos_int, "positive", zero=zero) +__all__ += ["floats", "int_range", "ints", "ints_range", "neg_float", "neg_floats", "negative_float", "negative_floats", + "neg_int", "neg_ints", "negative_int", "negative_ints", "pos_float", "pos_floats", "positive_float", + "positive_floats", "pos_int", "positive_int", "pos_ints", "positive_ints", "prime_number", "values_list"] + + +def __n(ntype): + def _wrapper(l, check_func=lambda x: False, idescr=None, shouldbe=None, **kwargs): + """ Parses a comma-separated list of ints. """ + l = _str2list(l) + if not all(check_func(x, **kwargs) for x in l): + msg = f"{['Bad list of', 'Not a'][len(l) == 1]} {'' if idescr is None else idescr + ' '}{ntype}" \ + f"{['s', ''][len(l) == 1]}" + if shouldbe is not None: + msg += f" (should be {shouldbe})" + raise ValueError(msg) + return l + return _wrapper + +floats = lambda l: __n("float")(l, is_float) +negative_float = neg_float = lambda i, zero=False: __n("float")(i, is_neg_float, "negative", zero=zero)[0] +positive_float = pos_float = lambda i, zero=True: __n("float")(i, is_pos_float, "positive", zero=zero)[0] +negative_floats = neg_floats = lambda l, zero=False: __n("float")(l, is_neg_float, "negative", zero=zero) +positive_floats = pos_floats = lambda l, zero=True: __n("float")(l, is_pos_float, "positive", zero=zero) +floats.__name__ = "floats" +negative_float.__name__ = neg_float.__name__ = "negative float" +negative_floats.__name__ = neg_floats.__name__ = "negative floats list" +positive_float.__name__ = pos_float.__name__ = "positive float" +positive_floats.__name__ = pos_floats.__name__ = "positive floats list" + +ints = lambda l: __n("integer")(l, is_int) +int_range = lambda i, i1, i2=None: __n("integer")(i, is_int_range, "valid", "in range [%d,%d]" % \ + (0 if i2 is None else i1, i1 if i2 is None else i2), i1=i1, i2=i2)[0] +negative_int = neg_int = lambda i, zero=False: __n("integer")(i, is_neg_int, "negative", zero=zero)[0] +positive_int = pos_int = lambda i, zero=True: __n("integer")(i, is_pos_int, "positive", zero=zero)[0] +ints_range = lambda l, i1, i2=None: __n("integer")(l, is_int_range, "valid", "in range [%d,%d]" % \ + (0 if i2 is None else i1, i1 if i2 is None else i2), i1=i1, i2=i2) +negative_ints = neg_ints = lambda l, zero=False: __n("integer")(l, is_neg_int, "negative", zero=zero) +positive_ints = pos_ints = lambda l, zero=True: __n("integer")(l, is_pos_int, "positive", zero=zero) ints.__name__ = "integers" int_range.__name__ = "integer (from range)" ints_range.__name__ = "integers list (from range)" diff --git a/src/tinyscript/helpers/timeout.py b/src/tinyscript/helpers/timeout.py index 2970fe4..671a91d 100644 --- a/src/tinyscript/helpers/timeout.py +++ b/src/tinyscript/helpers/timeout.py @@ -8,11 +8,7 @@ from ..preimports import signal -__all__ = __features__ = ["timeout", "Timeout", "TimeoutError"] - - -class TimeoutError(Exception): - pass # TimeoutError is not handled in Python 2 +__all__ = __features__ = ["timeout", "Timeout"] class Timeout(object): @@ -40,6 +36,7 @@ def __exit__(self, exc_type, exc_value, exc_traceback): raise NotImplementedError("signal.SIGALRM does not exist in Windows") else: signal.signal(signal.SIGALRM, signal.SIG_IGN) + signal.alarm(0) return not self.stop def _handler(self, signum, frame): diff --git a/tests/test_features_timing.py b/tests/test_features_timing.py index 5f0e348..271f029 100644 --- a/tests/test_features_timing.py +++ b/tests/test_features_timing.py @@ -5,7 +5,6 @@ import time from tinyscript.features.timing import set_time_items -from tinyscript.helpers.timeout import TimeoutError from utils import * diff --git a/tests/test_helpers_data_types.py b/tests/test_helpers_data_types.py index b7cca9f..7595e9b 100644 --- a/tests/test_helpers_data_types.py +++ b/tests/test_helpers_data_types.py @@ -66,7 +66,9 @@ def test_general_purpose_types(self): self.assertEqual(int_range(2, 1, 5), 2) self.assertRaises(ValueError, int_range, 5, 3) self.assertRaises(ValueError, int_range, 5, 1, 3) + self.assertEqual(neg_float(-1.), -1.) self.assertEqual(neg_int(-1), -1) + self.assertEqual(negative_float(-1.), -1.) self.assertEqual(negative_int(-1), -1) self.assertRaises(ValueError, neg_int, 0) self.assertRaises(ValueError, neg_int, 1) @@ -90,6 +92,7 @@ def test_general_purpose_types(self): self.assertRaises(ValueError, ints_range, "0,1]", 1, 2) self.assertRaises(ValueError, ints_range, ["a", 1], 1, 2) self.assertEqual(neg_ints("-1"), [-1]) + self.assertEqual(negative_floats("[-1.,-2.]"), [-1., -2.]) self.assertEqual(negative_ints("[-1,-2]"), [-1, -2]) self.assertRaises(ValueError, neg_ints, "-1,-2]") self.assertRaises(ValueError, neg_ints, [-1, 1]) @@ -225,6 +228,9 @@ def test_network_related_types(self): self.assertRaises(ValueError, as_number, ASN3) def test_data_type_check(self): + self.assertTrue(is_float(1.)) + self.assertFalse(is_float(1)) + self.assertFalse(is_float("a")) self.assertTrue(is_int(1)) self.assertFalse(is_int("a")) self.assertTrue(is_int_range(1, 1, 2)) @@ -235,10 +241,13 @@ def test_data_type_check(self): self.assertFalse(is_percentage(2)) self.assertTrue(is_percentage(.1)) self.assertFalse(is_percentage(".123")) + self.assertTrue(is_pos_float(10.)) + self.assertTrue(is_pos_float(0., True)) self.assertTrue(is_pos_int(10)) self.assertTrue(is_pos_int(0, True)) self.assertFalse(is_pos_int(0, False)) self.assertFalse(is_pos_int(-10)) + self.assertTrue(is_neg_float(-10.)) self.assertTrue(is_neg_int(-10)) self.assertFalse(is_neg_int(10)) for i in ["a", 2.2, 10, 145, 1537]: diff --git a/tests/test_helpers_timeout.py b/tests/test_helpers_timeout.py index fd47379..605a2b2 100644 --- a/tests/test_helpers_timeout.py +++ b/tests/test_helpers_timeout.py @@ -2,7 +2,7 @@ """Timeout utility assets' tests. """ -from tinyscript.helpers.timeout import timeout, Timeout, TimeoutError +from tinyscript.helpers.timeout import timeout, Timeout from utils import * diff --git a/tests/test_preimports_code.py b/tests/test_preimports_code.py index 9422d48..aa37071 100644 --- a/tests/test_preimports_code.py +++ b/tests/test_preimports_code.py @@ -40,7 +40,7 @@ def test_function_line_operations(self): code.replace_line(dummy2, 1, "# useless modified comment") self.assertIn("useless modified comment", code.source(dummy2)) code.add_line(dummy2, 1, "# another useless comment before first") - code.add_line(dummy2, 2, "pass", after=True) + code.insert_line(dummy2, 2, "pass", after=True) self.assertEqual(len(code.source(dummy2).split("\n")), 5) code.remove_line(dummy2, -1) self.assertIsNone(dummy2()) @@ -61,11 +61,11 @@ def test_function_line_operations(self): code.add_lines(dummy2, -1, "return 12345", -2, "# this return will not execute") self.assertEqual(len(code.source(dummy2).split("\n")), 6) self.assertEqual(dummy2(), 84) - code.add_line(dummy2, 1, "return 3*42") + code.insert_line(dummy2, 1, "return 3*42") self.assertEqual(dummy2(), 126) - code.add_line(dummy2, 1, "return 4*42", after=True) + code.insert_line(dummy2, 1, "return 4*42", after=True) self.assertEqual(dummy2(), 126) - code.add_line(dummy2, 0, "# dummy function") + code.insert_line(dummy2, 0, "# dummy function") self.assertEqual(len(code.source(dummy2).split("\n")), 9) code.delete_lines(dummy2, -1, -2, -3, -4) self.assertEqual(len(code.source(dummy2).split("\n")), 5)