-source .venv/bin/activate || source .venv/Scripts/activate
+source .venv/bin/activate
unset PS1
strategy:
matrix:
- python-version: ["3.5", "3.8", "3.10"]
+ python-version: ["3.10"]
steps:
- name: Checkout
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 }}
- "**"
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
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 ?=
**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.
See ``usda`` database: https://github.com/nutratech/usda-sqlite
+
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
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)
(**Specify:** flag ``-U`` to upgrade, or ``--pre`` for development releases)
+
Using the source code directly
#######################################################
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
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
#######################################################
make format lint test
+
ArgComplete (tab completion / autocomplete)
#######################################################
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
- Flavonoid, Isoflavonoids, and Proanthocyanidins **[1352 foods]**
+
Usage
#######################################################
# 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"
"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]"
"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
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 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.
_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.
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.
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)
)
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),
+ )
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
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"""