small fixes (#20) 20/head
authorShane Jaroch <chown_tee@proton.me>
Sat, 8 Apr 2023 14:25:54 +0000 (10:25 -0400)
committerShane Jaroch <chown_tee@proton.me>
Mon, 1 May 2023 21:42:42 +0000 (17:42 -0400)
no windows /Scripts in envrc

readme and require direnv in init

add note in old requirements, see TODO in setup.py

fix python3.4 sorting issue, add todos

shift error message over one column

update casey butt coefficients

only need 3.4 on windows, linux covers 3.10

skip 3.5 and 3.8, because 3.4 is already tested

.envrc
.github/workflows/install-linux.yml
.github/workflows/install-win32.yml
Makefile
README.rst
ntclient/__init__.py
ntclient/argparser/__init__.py
ntclient/argparser/funcs.py
ntclient/services/calculate.py
requirements-old.txt
tests/test_cli.py

diff --git a/.envrc b/.envrc
index b694c1941653dd38b2dfaabf465f81a1efb3da24..1c21d048064326a73b79d9781533985679ea14ef 100644 (file)
--- a/.envrc
+++ b/.envrc
@@ -1,2 +1,2 @@
-source .venv/bin/activate || source .venv/Scripts/activate
+source .venv/bin/activate
 unset PS1
index ca22d1cf6d08508f79e88db7c8f2962df20bbf69..de6fa69b3b4791969dbb772c34038541cc8e7c22 100644 (file)
@@ -15,7 +15,7 @@ jobs:
 
     strategy:
       matrix:
-        python-version: ["3.5", "3.8", "3.10"]
+        python-version: ["3.10"]
 
     steps:
       - name: Checkout
@@ -23,7 +23,7 @@ jobs:
         with:
           submodules: recursive
 
-      - name: Set up Python ${{ matrix.python-version }} & Restore Cache
+      - name: Set up Python ${{ matrix.python-version }}
         uses: actions/setup-python@v4
         with:
           python-version: ${{ matrix.python-version }}
index 9323928a618eaf57363a38c4d74499ffc248a75d..59b0a6a854a838d0b5415439e54ed03b4e14fbfc 100644 (file)
@@ -8,25 +8,37 @@ name: install-win32
       - "**"
 
 jobs:
-  windows-latest:
+  python:
     runs-on: [windows-latest]
 
+    strategy:
+      matrix:
+        python-version: ["3.4"]
+
     steps:
       - name: Checkout
         uses: actions/checkout@v3
         with:
           submodules: recursive
 
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ matrix.python-version }}
+          # update-environment: false
+
       - name: Reload Cache / pip
         uses: actions/cache@v3
         with:
           path: ~\AppData\Local\pip\Cache
           # NOTE: only cares about base requirements.txt
-          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          # yamllint disable rule:line-length
+          key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('**/requirements.txt') }}
+          # yamllint enable rule:line-length
           restore-keys: |
-            ${{ runner.os }}-pip-
+            ${{ runner.os }}-${{ matrix.python-version }}-pip-
 
-      - name: Install
+      - name: Install CLI
         run: make install
 
       - name: Basic Tests / CLI / Integration
index 8d94520c23a5f8f5debaae68741fdb162f268590..9d9321833f34ea11776ae40e9643f8bf07dcf086 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ init: ## Set up a Python virtual environment
        rm -rf .venv
        ${PY_SYS_INTERPRETER} -m venv .venv
        - if [ -z "${CI}" ]; then ${PY_SYS_INTERPRETER} -m venv --upgrade-deps .venv; fi
-       direnv allow
+       direnv allow
 
 # include .env
 SKIP_VENV ?=
index 50699c04aba6c4afc96cba1c627769e690373d74..84d70e6b876074beeb995d12d1e566f516e0dd72 100644 (file)
@@ -9,8 +9,8 @@ and mapping rules built on top.
 
 **Requires:**
 
-- Python 3.4.0 or later (``lzma``, ``ssl`` & ``sqlite3`` modules)
-  [Win XP / Ubuntu 14.04].
+- Python 3.4.3 or later (``lzma``, ``ssl`` & ``sqlite3`` modules)
+  [WinXP, Ubuntu14.04, or later].
 - Packages: see ``setup.py``, and ``requirements.txt`` files.
 - Internet connection, to download food database & package dependencies.
 
@@ -19,6 +19,7 @@ See ``nt`` database:   https://github.com/nutratech/nt-sqlite
 See ``usda`` database: https://github.com/nutratech/usda-sqlite
 
 
+
 Details
 #######################################################
 
@@ -69,52 +70,41 @@ Details
     -
 
 
+
 Linux / macOS requirements (for development)
 #######################################################
 
-You will need to install ``make`` and ``gcc`` to build the ``Levenshtein``
-extension.
-
-::
-
-  sudo apt install \
-    make gcc \
-    python3-dev python3-venv \
-    direnv
-
+You will need ``make`` and ``gcc`` to build the ``Levenshtein`` extension.
 
-You can add the ``direnv`` hook, ``direnv hook bash >>~/.bashrc``.
-Only run this once.
+.. code-block:: bash
 
+  sudo apt install make gcc direnv python3-dev python3-venv
 
-Plugin Development
-#######################################################
+  # on macOS
+  brew install make gcc direnv python@3.10
 
-You can develop plugins (or data modifications sets) that
-are imported and built on the base (or core) installation.
 
-These currently can take the form of custom recipes, foods, and RDA injection.
+Using ``direnv``
+~~~~~~~~~~~~~~~~
 
+Install with,
 
-Supporting Old Versions of Python
-#######################################################
+.. code-block:: bash
 
-The old requirements can still be tested on modern interpreters.
-Simply install them with this (inside your ``venv`` environment).
+    sudo apt install direnv || brew install direnv
 
-::
+    # Need to add hook, too
+    # See: https://direnv.net/docs/hook.html
+    DEFAULT_SHELL=$(basename $SHELL)
+    SHELL_RC_FILE=~/.${DEFAULT_SHELL}rc
+    HOOK='eval "$(direnv hook '$DEFAULT_SHELL')"'
 
-  pip install -r requirements-old.txt
+    # Install the hook, if not already
+    grep "$HOOK" $SHELL_RC_FILE || echo "$HOOK" >>$SHELL_RC_FILE
+    source $SHELL_RC_FILE
 
-This won't guarantee compatibility for every version, but it will help.
-We provide a wide range. The oldest version of ``tabulate`` is from 2013.
+This is what the ``.envrc`` file is for. It automatically activates ``venv``.
 
-There is automated testing on GitHub, but to use an old interpreter
-(Python 3.4 does not have the ``typing`` module! Only ``collections.abc``),
-you may need to use a virtual machine or install old SSL libraries or enter a
-similar messy state.
-My preference is for VirtualBox images, where I manually test *Windows XP*
-& *Ubuntu 14.04*.
 
 
 Notes
@@ -124,24 +114,22 @@ On Windows you should check the box during the Python installer
 to include ``Scripts`` directory in your ``%PATH%``.  This can be done
 manually after installation too.
 
-Windows users may also have differing results if they install for all users
-(as an administrator) vs. installing just for themselves. It may change the
-location of installed scripts, and affect the ``$PATH`` variable being
-correctly populated for prior installs.
+Main program works 100% on older OSes, but ``test`` and ``lint`` may break.
+
 
-Install the Levenshtein speedup with this. If it fails remove the ``[extras]``.
+Levenshtein speedup [extras]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Install the Levenshtein speedup with this.
 
 .. code-block:: bash
 
   pip install nutra[extras]
 
-Linux may need to install ``python-dev`` package to build
-``python-Levenshtein``.
+Linux may need to install ``python-dev`` package as well as ``gcc``.
 
-Windows users may not be able to install ``python-Levenshtein``.
+Windows may fail if missing the ``Visual Studio`` build tools are missing.
 
-Main program works 100%, but ``test`` and ``lint`` may break on older operating
-systems (*Ubuntu 14.04*, *Windows XP*).
 
 
 Install PyPi release (from pip)
@@ -154,6 +142,7 @@ Install PyPi release (from pip)
 (**Specify:** flag ``-U`` to upgrade, or ``--pre`` for development releases)
 
 
+
 Using the source code directly
 #######################################################
 
@@ -163,8 +152,7 @@ Clone down, initialize ``nt-sqlite`` submodule, and install requirements:
 
   git clone https://github.com/nutratech/cli.git
   cd cli
-  make init
-  # source .venv/bin/activate  # uncomment if NOT using direnv
+  make init || source .venv/bin/activate
   make deps
 
   ./nutra -h
@@ -188,16 +176,17 @@ with ``python -m ntclient``.
 You may need to set the ``PY_SYS_INTERPRETER`` value for the ``Makefile``
 if trying to install other than with ``/usr/bin/python3``.
 
+
 Building the PyPi release (sdist)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 .. code-block:: bash
 
-  # source .venv/bin/activate  # uncomment if NOT using direnv
   make build  # python3 setup.py --quiet sdist
   twine upload dist/nutra-X.X.X.tar.gz
 
 
+
 Linting & Tests
 #######################################################
 
@@ -209,6 +198,7 @@ Install the dependencies (``make deps``). Now you can lint & test.
   make format lint test
 
 
+
 ArgComplete (tab completion / autocomplete)
 #######################################################
 
@@ -253,9 +243,11 @@ And my ``~/.bashrc`` file looks like this.
       source ~/.bash_completion.d/python-argcomplete
   fi
 
+On older versions it may be ``python-argcomplete.sh`` instead.
 
 **NOTE:** Standard autocomplete is fully functional, we are adding customized
-completions
+completions.
+
 
 
 Currently Supported Data
@@ -270,6 +262,7 @@ Currently Supported Data
 - Flavonoid, Isoflavonoids, and Proanthocyanidins  **[1352 foods]**
 
 
+
 Usage
 #######################################################
 
index eb03714db4c0af045c3ffa4c70dbcab3bd8b582b..f03cc386b6b094692b1e8c9b753d08255c466c15 100644 (file)
@@ -16,7 +16,7 @@ from ntclient.ntsqlite.sql import NT_DB_NAME
 
 # Package info
 __title__ = "nutra"
-__version__ = "0.2.7.dev3"
+__version__ = "0.2.7.dev4"
 __author__ = "Shane Jaroch"
 __email__ = "chown_tee@proton.me"
 __license__ = "GPL v3"
index 86a5f67b56e963ab66984a14110e42a79bff0f61..b2f874132bbafab962161d222cca49e96953adef 100644 (file)
@@ -308,7 +308,7 @@ def build_calc_subcommand(subparsers: argparse._SubParsersAction) -> None:
         "desired_bf",
         type=float,
         nargs="?",
-        help="e.g. 0.12 -[eric_helms & casey_butt]",
+        help="e.g.  0.12 [eric_helms & casey_butt]",
     )
     calc_lbl_parser.add_argument(
         "wrist", type=float, nargs="?", help="wrist (cm) [casey_butt]"
index f29573017610d9495f5dba4b7238676a969bc0c0..aa177de077eb731b44b4054dc47d85b8ce34101d 100644 (file)
@@ -316,15 +316,14 @@ def calc_lbm_limits(args: argparse.Namespace) -> tuple:
         "calf",
     ]
     rows = []
-    for _calc, _result in result.items():
-        _values = list(_result.values())
+    for _calc in ["berkhan", "helms", "casey"]:
         row = [_calc]
-        row.extend(_values)
+        row.extend(result[_calc])
         while len(row) < len(headers):
             row.append(str())
         rows.append(row)
 
-    _table = tabulate(rows, headers=headers, tablefmt="pretty")
+    _table = tabulate(rows, headers=headers, tablefmt="simple")
     print(_table)
 
     return 0, result
index ff4e428c2e1e3ad8fb6846f87ae3708d3c1f1089..8fc93228f08f190789175a84f51fcc0ae5c722f1 100644 (file)
@@ -403,7 +403,7 @@ def bf_7site(gender: Gender, args: argparse.Namespace) -> float:
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Lean body limits (young men)
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-def lbl_berkhan(height: float) -> dict:
+def lbl_berkhan(height: float) -> tuple:
     """
     Calculate Martin Berkhan's lean body limit for young men.
 
@@ -415,10 +415,15 @@ def lbl_berkhan(height: float) -> dict:
 
     _min = round((height - 102) * 2.205, 1)
     _max = round((height - 98) * 2.205, 1)
-    return {"condition": "Contest shape (5-6%)", "weight": "%s ~ %s lbs" % (_min, _max)}
+    return (
+        # condition
+        "Contest shape (5-6%)",
+        # weight
+        "%s ~ %s lbs" % (_min, _max),
+    )
 
 
-def lbl_eric_helms(height: float, args: argparse.Namespace) -> dict:
+def lbl_eric_helms(height: float, args: argparse.Namespace) -> tuple:
     """
     Calculate Eric Helm's lean body limit for young men.
 
@@ -432,17 +437,26 @@ def lbl_eric_helms(height: float, args: argparse.Namespace) -> dict:
     try:
         desired_bf = float(args.desired_bf) * 100
     except (KeyError, TypeError):  # pragma: no cover
-        return {"errMsg": "Eric Helms failed, requires: height, desired_bf."}
+        # FIXME: define a `warning()` method with bold yellow text. Omit empty columns?
+        print("WARN: Eric Helms failed, requires: height, desired_bf.")
+        return (
+            # condition (blank)
+            str(),
+            # failure message (goes in "weight" column)
+            "Eric Helms failed!",
+        )
 
     _min = round(4851.00 * height * 0.01 * height * 0.01 / (100.0 - desired_bf), 1)
     _max = round(5402.25 * height * 0.01 * height * 0.01 / (100.0 - desired_bf), 1)
-    return {
-        "condition": "%s%% body fat" % desired_bf,
-        "weight": "%s ~ %s lbs" % (_min, _max),
-    }
+    return (
+        # condition
+        "%s%% body fat" % desired_bf,
+        # weight
+        "%s ~ %s lbs" % (_min, _max),
+    )
 
 
-def lbl_casey_butt(height: float, args: argparse.Namespace) -> dict:
+def lbl_casey_butt(height: float, args: argparse.Namespace) -> tuple:
     """
     Calculate Casey Butt's lean body limit for young men. Includes muscle measurements.
     Some may find these controversial.
@@ -461,9 +475,13 @@ def lbl_casey_butt(height: float, args: argparse.Namespace) -> dict:
         wrist = float(args.wrist) / 2.54  # convert cm --> inches
         ankle = float(args.ankle) / 2.54  # convert cm --> inches
     except (KeyError, TypeError):  # pragma: no cover
-        return {
-            "errMsg": "Casey Butt failed, requires: height, desired_bf, wrist, & ankle."
-        }
+        print("WARN: Casey Butt failed, requires: height, desired_bf, wrist, & ankle.")
+        return (
+            # condition (blank)
+            str(),
+            # failure message (goes in "weight" column)
+            "Casey Butt failed!",
+        )
 
     lbm = round(
         height ** (3 / 2)
@@ -473,14 +491,23 @@ def lbl_casey_butt(height: float, args: argparse.Namespace) -> dict:
     )
     weight = round(lbm / (1 - desired_bf), 1)
 
-    return {
-        "condition": "%s%% body fat" % (desired_bf * 100),
-        "weight": "%s lbs" % weight,
-        "lbm": "%s lbs" % lbm,
-        "chest": round(1.6817 * wrist + 1.3759 * ankle + 0.3314 * height, 2),
-        "arm": round(1.2033 * wrist + 0.1236 * height, 2),
-        "forearm": round(0.9626 * wrist + 0.0989 * height, 2),
-        "neck": round(1.1424 * wrist + 0.1236 * height, 2),
-        "thigh": round(1.3868 * ankle + 0.1805 * height, 2),
-        "calf": round(0.9298 * ankle + 0.1210 * height, 2),
-    }
+    return (
+        # condition
+        "%s%% body fat" % (desired_bf * 100),
+        # weight
+        "%s lbs" % weight,
+        # lbm
+        "%s lbs" % lbm,
+        # chest
+        round(1.625 * wrist + 1.3682 * ankle + 0.3562 * height, 2),
+        # arm
+        round(1.1709 * wrist + 0.1350 * height, 2),
+        # forearm
+        round(0.950 * wrist + 0.1041 * height, 2),
+        # neck
+        round(1.1875 * wrist + 0.1301 * height, 2),
+        # thigh
+        round(1.4737 * ankle + 0.1918 * height, 2),
+        # calf
+        round(0.9812 * ankle + 0.1250 * height, 2),
+    )
index 88850019ea6de296e1736b17a768e483a78f6264..34d07332155f334b196ad3779a4e8124aa939d6a 100644 (file)
@@ -1,4 +1,8 @@
 argcomplete<=1.8.2
 colorama<=0.3.6
+# NOTE: seems to require 0.18.0 on ubuntu 14.04
 fuzzywuzzy==0.3.0
 tabulate<=0.4.3
+# NOTE: testing stuff
+#future-fstrings
+#typing
index 6623e0e6644c044abe4caf4da6ec0fb0523f770f..42d8c7ea3b4b1a258ee87b20253384f8880b6d64 100644 (file)
@@ -276,25 +276,19 @@ class TestCli(unittest.TestCase):
         args = arg_parser.parse_args(args="calc lbl 179 0.1 17.2 21.5".split())
         code, result = args.func(args)
         assert code == 0
-        assert result["berkhan"] == {
-            "condition": "Contest shape (5-6%)",
-            "weight": "169.8 ~ 178.6 lbs",
-        }
-        assert result["helms"] == {
-            "condition": "10.0% body fat",
-            "weight": "172.7 ~ 192.3 lbs",
-        }
-        assert result["casey"] == {
-            "condition": "10.0% body fat",
-            "weight": "196.3 lbs",
-            "lbm": "176.7 lbs",
-            "chest": 46.39,
-            "arm": 16.86,
-            "forearm": 13.49,
-            "neck": 16.45,
-            "thigh": 24.46,
-            "calf": 16.4,
-        }
+        assert result["berkhan"] == ("Contest shape (5-6%)", "169.8 ~ 178.6 lbs")
+        assert result["helms"] == ("10.0% body fat", "172.7 ~ 192.3 lbs")
+        assert result["casey"] == (
+            "10.0% body fat",
+            "196.3 lbs",
+            "176.7 lbs",
+            47.69,
+            17.44,
+            13.77,
+            17.21,
+            25.99,
+            17.11,
+        )
 
     def test_415_invalid_path_day_throws_error(self):
         """Ensures invalid path throws exception in `day` subcommand"""