]> Nutra Git (v1) - nutratech/cli.git/commitdiff
wip
authorShane Jaroch <chown_tee@proton.me>
Sun, 25 Feb 2024 20:13:18 +0000 (15:13 -0500)
committerShane Jaroch <chown_tee@proton.me>
Sun, 25 Feb 2024 20:13:18 +0000 (15:13 -0500)
ntclient/core/nutprogbar.py
ntclient/services/analyze.py
tests/test_cli.py

index f656886f5d6fba78fc19983e089e37b85ad304b2..12deac9308bb5254bd27b83205bce65418d64d70 100644 (file)
@@ -1,24 +1,37 @@
 """Temporary [wip] module for more visual (& colorful) RDA output"""
 
+from typing import Mapping
 
-def nutprogbar(
-    food_amts: dict,
-    food_analyses: list,
-    nutrients: dict,
+from ntclient.utils import CLI_CONFIG
+
+
+def nutrient_progress_bars(
+    _food_amts: Mapping[int, float],
+    _food_analyses: list,
+    _nutrients: Mapping[int, list],
     # grams: float = 100,
     width: int = 50,
 ) -> dict:
     """Returns progress bars, colorized, for foods analyses"""
 
-    def tally() -> None:
-        for nut in nut_percs:
-            # TODO: get RDA values from nt DB, tree node nested organization
-            print(nut)
+    def tally() -> int:
+        """Tally the progress bars, return n_skipped"""
+        n_skipped = 0
+        for nut in nut_percs.items():
+            nutr_id, nutr_val = nut
+            # Skip if nutr_val == 0.0
+            if not nutr_val:
+                n_skipped += 1
+                continue
+            # Print bars
+            print_nutrient_bar(nutr_id, nutr_val, _nutrients)
+        return n_skipped
 
-    # for _food_analysis in food_analyses:
-        print(_food_analysis)
+    for _food_analysis in _food_analyses:
+        print(_food_analysis)
     food_analyses_dict = {
-        x[0]: {y[1]: y[2] for y in food_analyses if y[0] == x[0]} for x in food_analyses
+        x[0]: {y[1]: y[2] for y in _food_analyses if y[0] == x[0]}
+        for x in _food_analyses
     }
 
     # print(food_ids)
@@ -26,21 +39,130 @@ def nutprogbar(
 
     nut_amts = {}
 
-    for food_id, grams in food_amts.items():
-        # r = grams / 100.0
+    for food_id, grams in _food_amts.items():
+        ratio = grams / 100.0
         analysis = food_analyses_dict[food_id]
         for nutrient_id, amt in analysis.items():
             if nutrient_id not in nut_amts:
-                nut_amts[nutrient_id] = amt
+                nut_amts[nutrient_id] = amt * ratio
             else:
-                nut_amts[nutrient_id] += amt
+                nut_amts[nutrient_id] += amt * ratio
 
     nut_percs = {}
 
     for nutrient_id, amt in nut_amts.items():
         # TODO: if not rda, show raw amounts?
-        if isinstance(nutrients[nutrient_id][1], float):
-            nut_percs[nutrient_id] = round(amt / nutrients[nutrient_id][1], 3)
+        if isinstance(_nutrients[nutrient_id][1], float):
+            # print(type(_nutrients[nutrient_id][1]), _nutrients[nutrient_id])
+            nut_percs[nutrient_id] = round(amt / _nutrients[nutrient_id][1], 3)
+        else:
+            print(type(_nutrients[nutrient_id][1]), _nutrients[nutrient_id])
+            continue
 
     tally()
     return nut_percs
+
+
+def print_nutrient_bar(
+    _n_id: int, _amount: float, _nutrients: Mapping[int, list]
+) -> tuple:
+    """Print a single color-coded nutrient bar"""
+    nutrient = _nutrients[_n_id]
+    rda = nutrient[1]
+    tag = nutrient[3]
+    unit = nutrient[2]
+    # anti = nutrient[5]
+    # hidden = nutrient[...?]
+
+    # TODO: get RDA values from nt DB, tree node nested organization
+    if not rda:
+        return False, nutrient
+    attain = _amount / rda
+    perc = round(100 * attain, 1)
+
+    if attain >= CLI_CONFIG.thresh_over:
+        color = CLI_CONFIG.color_over
+    elif attain <= CLI_CONFIG.thresh_crit:
+        color = CLI_CONFIG.color_crit
+    elif attain <= CLI_CONFIG.thresh_warn:
+        color = CLI_CONFIG.color_warn
+    else:
+        color = CLI_CONFIG.color_default
+
+    # Print
+    detail_amount = "{0}/{1} {2}".format(round(_amount, 1), rda, unit).ljust(18)
+    detail_amount = "{0} -- {1}".format(detail_amount, tag)
+    left_index = 20
+    left_pos = round(left_index * attain) if attain < 1 else left_index
+    print(" {0}<".format(color), end="")
+    print("=" * left_pos + " " * (left_index - left_pos) + ">", end="")
+    print(" {0}%\t[{1}]".format(perc, detail_amount), end="")
+    print(CLI_CONFIG.style_reset_all)
+
+    return True, perc
+
+
+def print_macro_bar(
+    _fat: float, _net_carb: float, _pro: float, _kcals_max: float, _buffer: int = 0
+) -> None:
+    """Print macro-nutrients bar with details."""
+    _kcals = _fat * 9 + _net_carb * 4 + _pro * 4
+
+    p_fat = (_fat * 9) / _kcals
+    p_car = (_net_carb * 4) / _kcals
+    p_pro = (_pro * 4) / _kcals
+
+    # TODO: handle rounding cases, tack on to, or trim off FROM LONGEST ?
+    mult = _kcals / _kcals_max
+    n_fat = round(p_fat * _buffer * mult)
+    n_car = round(p_car * _buffer * mult)
+    n_pro = round(p_pro * _buffer * mult)
+
+    # Headers
+    f_buf = " " * (n_fat // 2) + "Fat" + " " * (n_fat - n_fat // 2 - 3)
+    c_buf = " " * (n_car // 2) + "Carbs" + " " * (n_car - n_car // 2 - 5)
+    p_buf = " " * (n_pro // 2) + "Pro" + " " * (n_pro - n_pro // 2 - 3)
+    print(
+        "  "
+        + CLI_CONFIG.color_yellow
+        + f_buf
+        + CLI_CONFIG.color_blue
+        + c_buf
+        + CLI_CONFIG.color_red
+        + p_buf
+        + CLI_CONFIG.style_reset_all
+    )
+
+    # Bars
+    print(" <", end="")
+    print(CLI_CONFIG.color_yellow + "=" * n_fat, end="")
+    print(CLI_CONFIG.color_blue + "=" * n_car, end="")
+    print(CLI_CONFIG.color_red + "=" * n_pro, end="")
+    print(CLI_CONFIG.style_reset_all + ">")
+
+    # Calorie footers
+    k_fat = str(round(_fat * 9))
+    k_car = str(round(_net_carb * 4))
+    k_pro = str(round(_pro * 4))
+    f_buf = " " * (n_fat // 2) + k_fat + " " * (n_fat - n_fat // 2 - len(k_fat))
+    c_buf = " " * (n_car // 2) + k_car + " " * (n_car - n_car // 2 - len(k_car))
+    p_buf = " " * (n_pro // 2) + k_pro + " " * (n_pro - n_pro // 2 - len(k_pro))
+    print(
+        "  "
+        + CLI_CONFIG.color_yellow
+        + f_buf
+        + CLI_CONFIG.color_blue
+        + c_buf
+        + CLI_CONFIG.color_red
+        + p_buf
+        + CLI_CONFIG.style_reset_all
+    )
+
+
+def print_header(_header: str) -> None:
+    """Print a colorized header"""
+    print(CLI_CONFIG.color_default, end="")
+    print("=" * (len(_header) + 2 * 5))
+    print("-->  %s  <--" % _header)
+    print("=" * (len(_header) + 2 * 5))
+    print(CLI_CONFIG.style_reset_all)
index bdb4aff47adc8c4aaf94652d5d278d4009691793..e1ea96df62a11d57b9a55e47ced5ed492a2bcf0b 100644 (file)
@@ -19,7 +19,12 @@ from ntclient import (
     NUTR_ID_KCAL,
     NUTR_ID_PROTEIN,
 )
-from ntclient.core.nutprogbar import nutprogbar
+from ntclient.core.nutprogbar import (
+    nutrient_progress_bars,
+    print_header,
+    print_macro_bar,
+    print_nutrient_bar,
+)
 from ntclient.persistence.sql.usda.funcs import (
     sql_analyze_foods,
     sql_food_details,
@@ -132,14 +137,14 @@ def foods_analyze(food_ids: set, grams: float = 100) -> tuple:
         # TODO: nested, color-coded tree view
         # TODO: either make this function singular, or handle plural logic here
         _food_id = list(food_ids)[0]
-        nutprogbar(
+        nutrient_progress_bars(
             {_food_id: grams},
             [(_food_id, x[0], x[1]) for x in analyses[_food_id]],
             nutrients,
         )
         # BEGIN: deprecated code
-        table = tabulate(nutrient_rows, headers=headers, tablefmt="presto")
-        print(table)
+        table = tabulate(nutrient_rows, headers=headers, tablefmt="presto")
+        print(table)
         # END: deprecated code
         nutrients_rows.append(nutrient_rows)
 
@@ -230,110 +235,11 @@ def day_analyze(day_csv_paths: Sequence[str], rda_csv_path: str = str()) -> tupl
     return 0, nutrients_totals
 
 
-def print_macro_bar(
-    _fat: float, _net_carb: float, _pro: float, _kcals_max: float, _buffer: int = 0
-) -> None:
-    """Print macro-nutrients bar with details."""
-    _kcals = _fat * 9 + _net_carb * 4 + _pro * 4
-
-    p_fat = (_fat * 9) / _kcals
-    p_car = (_net_carb * 4) / _kcals
-    p_pro = (_pro * 4) / _kcals
-
-    # TODO: handle rounding cases, tack on to, or trim off FROM LONGEST ?
-    mult = _kcals / _kcals_max
-    n_fat = round(p_fat * _buffer * mult)
-    n_car = round(p_car * _buffer * mult)
-    n_pro = round(p_pro * _buffer * mult)
-
-    # Headers
-    f_buf = " " * (n_fat // 2) + "Fat" + " " * (n_fat - n_fat // 2 - 3)
-    c_buf = " " * (n_car // 2) + "Carbs" + " " * (n_car - n_car // 2 - 5)
-    p_buf = " " * (n_pro // 2) + "Pro" + " " * (n_pro - n_pro // 2 - 3)
-    print(
-        "  "
-        + CLI_CONFIG.color_yellow
-        + f_buf
-        + CLI_CONFIG.color_blue
-        + c_buf
-        + CLI_CONFIG.color_red
-        + p_buf
-        + CLI_CONFIG.style_reset_all
-    )
-
-    # Bars
-    print(" <", end="")
-    print(CLI_CONFIG.color_yellow + "=" * n_fat, end="")
-    print(CLI_CONFIG.color_blue + "=" * n_car, end="")
-    print(CLI_CONFIG.color_red + "=" * n_pro, end="")
-    print(CLI_CONFIG.style_reset_all + ">")
-
-    # Calorie footers
-    k_fat = str(round(_fat * 9))
-    k_car = str(round(_net_carb * 4))
-    k_pro = str(round(_pro * 4))
-    f_buf = " " * (n_fat // 2) + k_fat + " " * (n_fat - n_fat // 2 - len(k_fat))
-    c_buf = " " * (n_car // 2) + k_car + " " * (n_car - n_car // 2 - len(k_car))
-    p_buf = " " * (n_pro // 2) + k_pro + " " * (n_pro - n_pro // 2 - len(k_pro))
-    print(
-        "  "
-        + CLI_CONFIG.color_yellow
-        + f_buf
-        + CLI_CONFIG.color_blue
-        + c_buf
-        + CLI_CONFIG.color_red
-        + p_buf
-        + CLI_CONFIG.style_reset_all
-    )
-
-
 def day_format(
     analysis: Mapping[int, float], nutrients: Mapping[int, list], buffer: int = 0
 ) -> None:
     """Formats day analysis for printing to console"""
 
-    def print_header(header: str) -> None:
-        print(CLI_CONFIG.color_default, end="")
-        print("=" * (len(header) + 2 * 5))
-        print("-->  %s  <--" % header)
-        print("=" * (len(header) + 2 * 5))
-        print(CLI_CONFIG.style_reset_all)
-
-    def print_nute_bar(
-        _n_id: int, amount: float, _nutrients: Mapping[int, list]
-    ) -> tuple:
-        nutrient = _nutrients[_n_id]
-        rda = nutrient[1]
-        tag = nutrient[3]
-        unit = nutrient[2]
-        # anti = nutrient[5]
-
-        if not rda:
-            return False, nutrient
-        attain = amount / rda
-        perc = round(100 * attain, 1)
-
-        if attain >= CLI_CONFIG.thresh_over:
-            color = CLI_CONFIG.color_over
-        elif attain <= CLI_CONFIG.thresh_crit:
-            color = CLI_CONFIG.color_crit
-        elif attain <= CLI_CONFIG.thresh_warn:
-            color = CLI_CONFIG.color_warn
-        else:
-            color = CLI_CONFIG.color_default
-
-        # Print
-        detail_amount = "{0}/{1} {2}".format(round(amount, 1), rda, unit).ljust(18)
-        detail_amount = "{0} -- {1}".format(detail_amount, tag)
-        left_index = 20
-        left_pos = round(left_index * attain) if attain < 1 else left_index
-        print(" {0}<".format(color), end="")
-        print("=" * left_pos + " " * (left_index - left_pos) + ">", end="")
-        print(" {0}%\t[{1}]".format(perc, detail_amount), end="")
-        print(CLI_CONFIG.style_reset_all)
-
-        return True, perc
-
     # Actual values
     kcals = round(analysis[NUTR_ID_KCAL])
     pro = analysis[NUTR_ID_PROTEIN]
@@ -373,7 +279,7 @@ def day_format(
     # Nutrition detail report
     print_header("Nutrition detail report")
     for n_id in analysis:
-        print_nute_bar(n_id, analysis[n_id], nutrients)
+        print_nutrient_bar(n_id, analysis[n_id], nutrients)
     # TODO: actually filter and show the number of filtered fields
     print(
         "work in progress...",
index ab85c4c61779ae1cf9bd7ebc706a7a1c0ed84ebc..9a0dd97e8881aa2c3dd28a98d3a93a656063d6b7 100644 (file)
@@ -431,7 +431,7 @@ class TestCli(unittest.TestCase):
         """Verifies colored/visual output is successfully generated"""
         analysis = usda_funcs.sql_analyze_foods(food_ids={1001})
         nutrients = usda_funcs.sql_nutrients_overview()
-        output = nutprogbar.nutprogbar(
-            food_amts={1001: 100}, food_analyses=analysis, nutrients=nutrients
+        output = nutprogbar.nutrient_progress_bars(
+            _food_amts={1001: 100}, _food_analyses=analysis, _nutrients=nutrients
         )
         assert output