+++ /dev/null
----
-rules:
- braces:
- min-spaces-inside: 0
- max-spaces-inside: 1
- brackets:
- min-spaces-inside: 0
- max-spaces-inside: 0
- colons:
- max-spaces-before: 0
- max-spaces-after: 1
- commas:
- max-spaces-before: 0
- min-spaces-after: 1
- max-spaces-after: 1
- comments:
- level: warning
- require-starting-space: yes
- min-spaces-from-content: 1
- comments-indentation:
- level: warning
- document-end: disable
- document-start:
- level: warning
- present: yes
- empty-lines:
- max: 2
- max-start: 0
- max-end: 0
- hyphens:
- max-spaces-after: 1
- indentation:
- spaces: 2
- indent-sequences: yes
- check-multi-line-strings: no
- key-duplicates: {}
- line-length:
- level: warning
- max: 80
- allow-non-breakable-words: yes
- new-line-at-end-of-file: { level: error }
- new-lines:
- type: unix
- trailing-spaces: {}
[ "$(PYTHON)" = "$(PWD)/.venv/bin/python" ] || [ "$(PYTHON)" = "$(PWD)/.venv/Scripts/python" ]
+
# ---------------------------------------
# Install requirements
# ---------------------------------------
REQ_TEST := requirements-test.txt
REQ_TEST_OLD := requirements-test-old.txt
+
PIP_OPT_ARGS ?=
.PHONY: _deps
LINT_LOCS := ntclient/ tests/ setup.py
-YAML_LOCS := ntclient/ntsqlite/.*.yml .github/workflows/ .*.yml
-# NOTE: yamllint ntclient/ntsqlite/.travis.yml ? (submodule)
# NOTE: doc8 ntclient/ntsqlite/README.rst ? (submodule)
.PHONY: _lint
_lint:
black --check $(LINT_LOCS)
# lint RST (last param is search term, NOT ignore)
doc8 --quiet *.rst ntclient/ntsqlite/*.rst
- # lint YAML
- yamllint $(YAML_LOCS)
# lint Python
bandit -q -c .banditrc -r $(LINT_LOCS)
mypy $(LINT_LOCS)
test: _venv _test ## Run CLI unittests
+
# ---------------------------------------
# SQLite submodule: nt-sqlite
# ---------------------------------------
# TODO: nt-sqlite/test
+
# ---------------------------------------
# Python build & install
# ---------------------------------------
nutra -v
+
# ---------------------------------------
# Clean
# ---------------------------------------
rm -rf build/
rm -rf nutra.egg-info/
rm -rf .pytest_cache/ .mypy_cache/
+ # Recursively find & remove
find ntclient/ tests/ \
-name \
__pycache__ \
| xargs rm -rf
+
# ---------------------------------------
# Extras
# ---------------------------------------
# Package info
__title__ = "nutra"
-__version__ = "0.2.6"
+__version__ = "0.2.7.dev0"
__author__ = "Shane Jaroch"
__email__ = "chown_tee@proton.me"
__license__ = "GPL v3"
COLOR_RED = colors.COLOR_RED
+# pylint: disable=too-few-public-methods,too-many-instance-attributes
class _CliConfig:
"""Mutable global store for configuration values"""
# 1 rep max
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# The only ones displayed in the result table
common_n_reps = (1, 2, 3, 5, 6, 8, 10, 12, 15, 20)
Source: https://workoutable.com/one-rep-max-calculator/
"""
- def one_rm() -> float:
- _un_rounded_result = weight * (1 + (reps - 1) / 30)
- return round(_un_rounded_result, 1)
+ # Compute the 1-rep max
+ one_rm = round(
+ weight * (1 + (reps - 1) / 30),
+ 1,
+ )
- def weight_max_reps(target_reps: float) -> float:
- _un_rounded_result = one_rm() * 30 / (29 + target_reps)
- return round(_un_rounded_result, 1)
+ def max_weight(target_reps: float) -> float:
+ """Used to calculate max weight for a given rep count, e.g. 205x3 or 135x15"""
+ return round(
+ one_rm * 30 / (29 + target_reps),
+ 1,
+ )
- maxes = {n_reps: weight_max_reps(n_reps) for n_reps in common_n_reps}
- return maxes
+ return {n_reps: max_weight(n_reps) for n_reps in common_n_reps}
def orm_brzycki(weight: float, reps: float) -> dict:
1 RM = weight * 36 / (37 - reps)
NOTE: Adjusted formula is below, with quadratic term.
+ This makes it more accurate in the 12-20 rep range.
- 1 RM = weight * 36 / (37 - reps + 0.005 * reps^2)
+ 1 RM = weight * 36 / (36.995 - reps + 0.005 * reps^2)
Source: https://workoutable.com/one-rep-max-calculator/
"""
- def _one_rm() -> float:
- _un_rounded_result = weight * 36 / (37 - reps + 0.005 * reps**2)
- return round(_un_rounded_result, 1)
-
- one_rm = _one_rm()
+ # Compute the 1-rep max
+ one_rm = round(
+ weight * 36 / (36.995 - reps + 0.005 * reps**2),
+ 1,
+ )
- def weight_max_reps(target_reps: float) -> float:
- _un_rounded_result = one_rm * (37 - target_reps + 0.005 * target_reps**2) / 36
- return round(_un_rounded_result, 1)
+ def max_weight(target_reps: float) -> float:
+ """Used to calculate max weight for a given rep count, e.g. 205x3 or 135x15"""
+ return round(
+ one_rm * (36.995 - target_reps + 0.005 * target_reps**2) / 36,
+ 1,
+ )
- maxes = {n_reps: weight_max_reps(n_reps) for n_reps in common_n_reps}
- return maxes
+ return {n_reps: max_weight(n_reps) for n_reps in common_n_reps}
def orm_dos_remedios(weight: float, reps: int) -> dict:
Returns dict {n_reps: max_weight, ...}
for n_reps: (1, 2, 3, 5, 6, 8, 10, 12, 15, 20)
- Or an {"errMsg": "INVALID_RANGE", ...}
+ This is a manual data set, curated by dos Remedios;
+ the added values are provided by Mathematica's spline interpolation.
Source:
https://www.peterrobertscoaching.com/blog/the-best-way-to-calculate-1-rep-max
"""
- _common_n_reps = {
+ _max_rep_ratios = {
1: 1,
2: 0.92,
3: 0.9,
20: 0.55, # NOTE: I added this, 20 reps is NOT in the original equation.
}
- def _one_rm() -> float:
- _multiplier = _common_n_reps[reps]
- _un_rounded_result = weight / _multiplier
- return round(_un_rounded_result, 1)
-
# Compute the 1-rep max
- one_rm = _one_rm()
+ # NOTE: this should be guaranteed by arg-parse to be an integer, and 0 < n <= 20
+ one_rm = round(
+ weight / _max_rep_ratios[reps],
+ 1,
+ )
def max_weight(target_reps: int) -> float:
- """Used to calculate max weight based on actual reps, e.g. 5 or 12"""
- _multiplier = _common_n_reps[target_reps]
- _un_rounded_result = one_rm * _multiplier
- return round(_un_rounded_result, 1)
+ """Used to calculate max weight for a given rep count, e.g. 205x3 or 135x15"""
+ return round(
+ one_rm * _max_rep_ratios[target_reps],
+ 1,
+ )
- return {n_reps: max_weight(n_reps) for n_reps in _common_n_reps}
+ return {n_reps: max_weight(n_reps) for n_reps in common_n_reps}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows the safe avoidance of ImportError on non-colorama capable systems.
"""
-try:
- from colorama import Fore, Style
- from colorama import init as colorama_init
+# pylint: disable=invalid-name
+
+
+# pylint: disable=too-few-public-methods
+class _STYLE:
+ def __init__(self) -> None:
+ self.BRIGHT = str()
+ self.DIM = str()
+ self.RESET_ALL = str()
- # Made it this far, so run the init function (which is needed on Windows)
- colorama_init()
- # Styles
- STYLE_BRIGHT = Style.BRIGHT
- STYLE_DIM = Style.DIM
- STYLE_RESET_ALL = Style.RESET_ALL
+# pylint: disable=too-few-public-methods,too-many-instance-attributes
+class _FORE:
+ def __init__(self) -> None:
+ self.WARN = str()
+ self.CRIT = str()
+ self.OVER = str()
+ self.DEFAULT = str()
- # Colors
- COLOR_WARN = Fore.YELLOW
- COLOR_CRIT = Style.DIM + Fore.RED
- COLOR_OVER = Style.DIM + Fore.MAGENTA
+ self.YELLOW = str()
+ self.BLUE = str()
+ self.RED = str()
+ self.MAGENTA = str()
- COLOR_DEFAULT = Fore.CYAN
+ self.GREEN = str()
+ self.CYAN = str()
- # Used in macro bars
- COLOR_YELLOW = Fore.YELLOW
- COLOR_BLUE = Fore.BLUE
- COLOR_RED = Fore.RED
- # Used by `tree.py` utility
- COLOR_GREEN = Fore.GREEN
- COLOR_CYAN = Fore.CYAN
+_Style = _STYLE()
+_Fore = _FORE()
+
+try:
+ from colorama import Fore, Style
+ from colorama import init as colorama_init
+
+ # Made it this far, so run the init function (which is needed on Windows)
+ colorama_init()
except ImportError:
- # These will all just be empty strings if colorama isn't installed
+ Fore, Style = _Fore, _Style # type: ignore
- # Styles
- STYLE_BRIGHT = str()
- STYLE_DIM = str()
- STYLE_RESET_ALL = str()
- # Colors
- COLOR_WARN = str()
- COLOR_CRIT = str()
- COLOR_OVER = str()
+# NOTE: These will all just be empty strings if colorama isn't installed
+# Styles
+STYLE_BRIGHT = Style.BRIGHT
+STYLE_DIM = Style.DIM
+STYLE_RESET_ALL = Style.RESET_ALL
- COLOR_DEFAULT = str()
+# Colors for Progress / RDA bar
+COLOR_WARN = Fore.YELLOW
+COLOR_CRIT = Style.DIM + Fore.RED
+COLOR_OVER = Style.DIM + Fore.MAGENTA
+COLOR_DEFAULT = Fore.CYAN
- COLOR_YELLOW = str()
- COLOR_BLUE = str()
- COLOR_RED = str()
+# Used in macro bars
+COLOR_YELLOW = Fore.YELLOW
+COLOR_BLUE = Fore.BLUE
+COLOR_RED = Fore.RED
- COLOR_GREEN = str()
- COLOR_CYAN = str()
+# Used by `tree.py` utility
+COLOR_GREEN = Fore.GREEN
+COLOR_CYAN = Fore.CYAN
types-psycopg2>=2.9.18
types-setuptools>=57.4.0
types-tabulate>=0.8.11
-yamllint>=1.27
r.recipe_overview("-12345-FAKE-PATH-")
def test_recipe_overview_might_succeed_for_maybe_existing_id(self):
- """Tries check for existing ID, but only can if the user initialized"""
+ """Tries 'check for existing ID', but only can if the user initialized"""
exit_code, _ = r.recipe_overview(
os.path.join(RECIPE_STOCK, "dinner", "burrito-bowl.csv")
)
assert len(servings_rows[0]) == 1
def test_410_nt_argparser_funcs(self):
- """Tests nt functions in argparser.funcs (to varying degrees each)"""
+ """
+ Tests nt functions in argparser.funcs (to varying degrees each)
+
+ TODO: split this up... separate argparser tests; then test missing service lines
+ """
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Day
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert result["sevenSite"] == 9.93
# Female test
- # TODO: better values, and don't require hip above (it's 0)
args = arg_parser.parse_args(
args="calc bf -F -a 29 -ht 178 -w 70 -hip 100 -n 35 "
"15 23 19 14 11 10 9".split()
args = arg_parser.parse_args(args="calc lbl 179 0.1 17.2 21.5".split())
code, result = args.func(args)
assert code == 0
- # NOTE: wip
- print(result)
+ 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,
+ }
def test_415_invalid_path_day_throws_error(self):
"""Ensures invalid path throws exception in `day` subcommand"""