about summary refs log tree commit diff
path: root/quality_control
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-02-12 12:10:44 +0300
committerFrederick Muriuki Muriithi2024-02-12 18:17:42 +0300
commit68696caeedde3636aff34db048a4490fbf51edf3 (patch)
tree8a7fd555aa6b867043a6e4cf662102a2a0d004fa /quality_control
parentabb55d7e03bf207ebf00b4c71f1bbdd8f58a0ad3 (diff)
downloadgn-uploader-68696caeedde3636aff34db048a4490fbf51edf3.tar.gz
Build generic decimal places checker.
Diffstat (limited to 'quality_control')
-rw-r--r--quality_control/checks.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/quality_control/checks.py b/quality_control/checks.py
new file mode 100644
index 0000000..28b9ab5
--- /dev/null
+++ b/quality_control/checks.py
@@ -0,0 +1,51 @@
+"""Quality control checks for data."""
+import re
+from typing import Optional
+
+def decimal_places_pattern(mini: int, maxi: Optional[int] = None) -> re.Pattern:
+    """
+    Generate a regular expression for checking numbers
+
+    Generates a regular expression that matches:
+    a) Whole numbers, e.g. 2, 54343, 25, etc
+    b) Zeroes e.g. 0, 000, 0.0, 0.000, 0.00000, etc
+    c) Numbers with at least 'mini' decimal places
+    d) If 'maxi' is provided, then numbers with decimal places between
+       'mini' and 'maxi'.
+
+    To test for a match of exactly 'n' decimal places, then both 'mini' and
+    'maxi' should be set to 'n'.
+
+    ARGUMENTS:
+    - mini [int]: The mini number of decimal places allowed. This is
+      mandatory.
+    - maxi [int]: The maxi number of decimal places allowed. This is an
+      optional argument. If not provided, then an infinite (theoretically)
+      number of decimal places is allowed.
+    """
+    try:
+        assert isinstance(mini, int), "The argument 'mini' MUST be a integer"
+        assert maxi is None or isinstance(maxi, int), "The argument 'maxi' MUST be a integer"
+    except AssertionError as exc:
+        raise TypeError(*exc.args) from exc
+
+    try:
+        assert mini > 0, "The argument 'mini' must be greater than zero (0)."
+        if isinstance(maxi, int):
+            assert maxi > 0, "The argument 'maxi' must be greater than zero (0)."
+            assert maxi >= mini, "'maxi' MUST be greater than or equal to 'mini'."
+    except AssertionError as exc:
+        raise ValueError(*exc.args) from exc
+
+    return re.compile(
+        r"^("
+        r"0+" # All zeroes, no decimal places
+        + r"|0+\.0+" # 0.00…
+        + r"|[0-9]+\.?0*" # Whole numbers, or all zeroes after decimal point
+        + r"|[0-9]+\.[0-9]{"
+        + str(mini)
+        + r","
+        + (str(maxi) if maxi is not None else r"")
+        + r"}"
+        + r")$"
+    )