--- /dev/null
+set PY_SYS_INTERPRETER=python3
.idea/
__sha__.py
*.sqlite
+.nutra*
####################
## Python Ignores ##
include requirements-*.txt
include ntclient/LICENSE
-include ntclient/CHANGELOG.md
+include ntclient/CHANGELOG.rst
include ntclient/ntsqlite/LICENSE
include ntclient/ntsqlite/README.rst
-include ntclient/ntsqlite/CHANGELOG.md
-graft ntclient/ntsqlite/sql/
+include ntclient/ntsqlite/CHANGELOG.rst
+include ntclient/ntsqlite/sql/*.sql
+include ntclient/ntsqlite/sql/data/*.csv
+include ntclient/ntsqlite/sql/upgrade_scripts/*.sql
-global-exclude *.sqlite3
+global-exclude nt.sqlite3
global-exclude __pycache__/*
init: ## Set up a Python virtual environment
git submodule update --init
if [ ! -d .venv ]; then \
- /usr/bin/python3 -m venv .venv; \
+ $(PY_SYS_INTERPRETER) -m venv .venv; \
fi
- direnv allow
@echo -e "\r\nNOTE: activate venv, and run 'make deps'\r\n"
# Install requirements
# ---------------------------------------
-PIP := python -m pip
+PY_SYS_INTERPRETER ?= /usr/bin/python3
+PY_VIRTUAL_INTERPRETER ?= python
+
+PIP ?= $(PY_VIRTUAL_INTERPRETER) -m pip
+
REQ_OPT := requirements-optional.txt
REQ_LINT := requirements-lint.txt
-REQ_TEST := tests/requirements.txt
-REQ_OLD := tests/requirements-win_xp-ubu1604.txt
+REQ_TEST := requirements-test.txt
+REQ_OLD := requirements-test-win_xp-ubu1604.txt
+
.PHONY: _deps
_deps:
$(PIP) install wheel
$(PIP) install -r requirements.txt
- $(PIP) install -r $(REQ_OPT)
- $(PIP) install -r $(REQ_LINT)
- - $(PIP) install -r $(REQ_TEST) || (echo "\r\nTEST REQs failed... try old version" && $(PIP) install -r $(REQ_OLD))
+ - $(PIP) install -r $(REQ_TEST) || (echo "\r\nTEST REQs failed. Trying old version" && $(PIP) install -r $(REQ_OLD))
.PHONY: deps
deps: _venv _deps ## Install requirements
black $(LINT_LOCS)
-LINT_LOCS := ntclient/ tests/ scripts/ nutra setup.py
+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: ntsqlite/build
ntsqlite/build:
- python ntclient/ntsqlite/sql/__init__.py
+ $(PY_SYS_INTERPRETER) ntclient/ntsqlite/sql/__init__.py
# TODO: nt-sqlite/test
# ---------------------------------------
-# Python build stuff
+# Python build & install
# ---------------------------------------
.PHONY: _build
_build:
- python setup.py --quiet sdist
+ $(PY_SYS_INTERPRETER) setup.py --quiet sdist
.PHONY: build
-build: _venv _build clean ## Create sdist binary *.tar.gz
-
-.PHONY: _install
-_install:
- python -m pip install wheel
- python -m pip install .
- python -m pip show nutra
- - python -c 'import shutil; print(shutil.which("nutra"));'
- nutra -v
+build: ## Create sdist binary *.tar.gz
+build: _build clean
-.PHONY: install
-install: _venv _install ## pip install nutra
-
-.PHONY: _uninstall
-_uninstall:
- python -m pip uninstall -y nutra
-.PHONY: uninstall
-uninstall: _venv _uninstall ## pip uninstall nutra
+.PHONY: install
+install: ## pip install nutra
+ $(PY_SYS_INTERPRETER) -m pip install wheel
+ $(PY_SYS_INTERPRETER) -m pip install .
+ $(PY_SYS_INTERPRETER) -m pip show nutra
+ - $(PY_SYS_INTERPRETER) -c 'import shutil; print(shutil.which("nutra"));'
+ nutra -v
# ---------------------------------------
*Requires:*
-- Python 3.4.0 or later (lzma, ssl & sqlite3 modules) [Win XP / Ubuntu 16.04]
-- Packages: see ``setup.py``, ``requirements.txt``, and ``config`` folder
-- Internet connection, to download food database & package dependencies
+- Python 3.4.0 or later (lzma, ssl & sqlite3 modules) [Win XP / Ubuntu 16.04].
+- Packages: see ``setup.py``, and ``requirements.txt`` files.
+- Internet connection, to download food database & package dependencies.
See nt database: https://github.com/nutratech/nt-sqlite
+++ /dev/null
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [Unreleased]
-
-### Added
-
-- Download cache & checksum verification
-- Basic functionality of `import` and `export` subcommands
-- `[DEVELOPMENT]` Added `Makefile` with easy commands for `init`, `lint`, `test`, etc
-
-## [0.2.2] - 2022-04-08
-
-### Added
-
-- Limit search & sort results to top `n` results (e.g. top 10 or top 100)
-- Enhanced terminal sizing (buffer termination)
-- Pydoc PAGING flag via `--no-pager` command line arg (with `set_flags()` method)
-- Check for appropriate `ntsqlite` database version
-- `[DEVELOPMENT]` Special `file_or_dir_path` and `file_path` custom type validators
- for argparse
-- `[DEVELOPMENT]` Added special requirements files for
- (`test`, `lint`, `optional` [Levenshtein], and `win_xp-test` [Python 3.4])
-- `[DEVELOPMENT]` Added `CHANGELOG.md` file
-
-### Changed
-
-- Print `exit_code` in DEBUG mode (`--debug` flag/arg)
-- Moved `subparsers` module in `ntclient.argparser` to `__init__`
-- Moved tests out of `ntclient/` and into `tests/` folder
-
-## [0.2.1] - 2021-05-30
-
-### Added
-
-- Python 3.4.3 support (Windows XP and Ubuntu 16.04)
-- Debug flag (`--debug | -d`) for all commands
-
-### Changed
-
-- Overall structure with main file and argparse methods
-- Use soft pip requirements `~=` instead of `==`
-- `DEFAULT` and `OVER` colors
-
-### Removed
-
-- guid columns from `ntsqlite` submodule
-
-## [0.2.0] - 2021-05-21
-
-### Added
-
-- SQLite support for `usda` and `nt` schemas (removed API calls to remote server)
-- Preliminary support for `recipe` and `bio` subcommands
-- On-boarding process with `init` subcommand
-- Support for `argcomplete` on `bash` (Linux/macOS)
-- Tests
-
-## [0.0.38] - 2020-08-01
-
-### Added
-
-- Support for analysis of day CSV files
--- /dev/null
+***********
+ Changelog
+***********
+
+All notable changes to this project will be documented in this file.
+
+The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.1.0/>`_,
+and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
+
+
+
+[Unreleased]
+########################################################################
+
+Added
+~~~~~
+
+- Basic functionality of ``import`` and ``export`` sub-commands
+
+
+
+[0.2.3] - 2022-07-12
+########################################################################
+
+Added
+~~~~~
+
+- ``[WIP]`` Download cache & checksum verification
+- ``[DEVELOPMENT]`` Added ``Makefile`` with easy commands for ``init``,
+ ``lint``, ``test``, etc
+- ``n`` as a shorthand script for ``nutra``
+
+Changed
+~~~~~~~
+
+- Rename to ``CHANGELOG.rst``
+
+Fixed
+~~~~~
+
+- Separate installer logic ``scripts`` & ``entry_points`` for Windows vs. Unix.
+
+Removed
+~~~~~~~
+
+- Some tables, e.g. ``biometric``. See ``nt-sqlite`` submodule for details.
+ This is still a work in progress to newer tables.
+
+
+
+[0.2.2] - 2022-04-08
+########################################################################
+
+Added
+~~~~~
+
+- Limit search & sort results to top ``n`` results (e.g. top 10 or top 100)
+- Enhanced terminal sizing (buffer termination)
+- ``Pydoc`` ``PAGING`` flag via ``--no-pager`` command line arg
+ (with ``set_flags()`` method)
+- Check for appropriate ``ntsqlite`` database version
+- ``[DEVELOPMENT]`` Special ``file_or_dir_path`` and ``file_path``
+ custom type validators for ``argparse``
+- ``[DEVELOPMENT]`` Added special requirements files for
+ (``test``, ``lint``, ``optional: Levenshtein``,
+ and ``win_xp-test`` [Python 3.4])
+- ``[DEVELOPMENT]`` Added ``CHANGELOG.md`` file
+
+Changed
+~~~~~~~
+
+- Print ``exit_code`` in DEBUG mode (`--debug` flag/arg)
+- Moved ``subparsers`` module in ``ntclient.argparser`` to ``__init__``
+- Moved tests out of ``ntclient/`` and into ``tests/`` folder
+
+
+
+[0.2.1] - 2021-05-30
+########################################################################
+
+Added
+~~~~~
+
+- Python 3.4 support (Windows XP and Ubuntu 16.04)
+- Debug flag (``--debug | -d``) for all commands
+
+Changed
+~~~~~~~
+
+- Overall structure with main file and argparse methods
+- Use soft pip requirements ``~=`` instead of ``==``
+- ``DEFAULT`` and ``OVER`` colors
+
+Removed
+~~~~~~~
+
+- ``guid`` columns from ``ntsqlite`` submodule
+
+
+
+[0.2.0] - 2021-05-21
+########################################################################
+
+Added
+~~~~~
+
+- SQLite support for ``usda`` and ``nt`` schemas
+ (removed API calls to remote server)
+- Preliminary support for ``recipe`` and ``bio`` subcommands
+- On-boarding process with ``init`` subcommand
+- Support for ``argcomplete`` on ``bash`` (Linux/macOS)
+- Tests
+
+
+
+[0.0.38] - 2020-08-01
+########################################################################
+
+Added
+~~~~~
+
+- Support for analysis of day CSV files
# Package info
__title__ = "nutra"
-__version__ = "0.2.3.dev1"
+__version__ = "0.2.3"
__author__ = "Shane Jaroch"
-__email__ = "nutratracker@gmail.com"
+__email__ = "chown_tee@proton.me"
__license__ = "GPL v3"
__copyright__ = "Copyright 2018-2022 Shane Jaroch"
__url__ = "https://github.com/nutratech/cli"
# Sqlite target versions
__db_target_nt__ = "0.0.5"
__db_target_usda__ = "0.0.8"
+USDA_XZ_SHA256 = "25dba8428ced42d646bec704981d3a95dc7943240254e884aad37d59eee9616a"
# Global variables
ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
-NUTRA_DIR = os.path.join(os.path.expanduser("~"), ".nutra")
+NUTRA_DIR = os.getenv("NUTRA_HOME", os.path.join(os.path.expanduser("~"), ".nutra"))
USDA_DB_NAME = "usda.sqlite"
-# NT_DB_NAME = "nt.sqlite" # defined in ntclient.ntsqlite.sql
+# NOTE: NT_DB_NAME = "nt.sqlite3" is defined in ntclient.ntsqlite.sql
DEBUG = False
PAGING = True
PY_MIN_STR = ".".join(str(x) for x in PY_MIN_VER)
PY_SYS_STR = ".".join(str(x) for x in PY_SYS_VER)
if PY_SYS_VER < PY_MIN_VER:
- print("ERROR: nutra requires Python %s or later to run" % PY_MIN_STR)
+ print("ERROR: %s requires Python %s or later to run" % (__title__, PY_MIN_STR))
print("HINT: You're running Python %s" % PY_SYS_STR)
sys.exit(1)
DEFAULT_DAY_H_BUFFER = BUFFER_WD - 4 if BUFFER_WD > 12 else 8
+# TODO: keep one extra row on winXP / cmd.exe, it cuts off
DECREMENT = 1 if platform.system() == "Windows" else 0
DEFAULT_SORT_H_BUFFER = (
BUFFER_WD - (38 + DECREMENT) if BUFFER_WD > 50 else (12 - DECREMENT)
)
+# NOTE: wip
+# class CLIConfig:
+# def __init__(self):
+# prop1 = True
+# usda_sqlite
+# nt_sqlitedriver
+
+
+# TODO:
+# Nested nutrient tree, like:
+# http://www.whfoods.com/genpage.php?tname=nutrientprofile&dbid=132
+# Attempt to record errors in failed try/catch block (bottom of __main__.py)
+# Make use of argcomplete.warn(msg) ?
+
+
def set_flags(args: argparse.Namespace) -> None:
"""
Sets
"""
global DEBUG, PAGING # pylint: disable=global-statement
DEBUG = args.debug
- PAGING = not args.no_paging
+ PAGING = not args.no_pager
if DEBUG:
print("Console size: %sh x %sw" % (BUFFER_HT, BUFFER_WD))
-
-
-# TODO:
-# nested nutrient tree, like: http://www.whfoods.com/genpage.php?tname=nutrientprofile&dbid=132
-# attempt to record errors in failed try/catch block (bottom of __main__.py)
-# make use of argcomplete.warn(msg) ?
https://pypi.org/project/nutra/
nutra is an extensible nutrient analysis and composition application.
-Copyright (C) 2018-2022 Shane Jaroch <nutratracker@gmail.com>
+Copyright (C) 2018-2022 Shane Jaroch <chown_tee@proton.me>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
"-d", "--debug", action="store_true", help="enable detailed error messages"
)
arg_parser.add_argument(
- "--no-pager",
- dest="no_paging",
- action="store_true",
- help="disable paging (print full output)",
+ "--no-pager", action="store_true", help="disable paging (print full output)"
)
# Subparsers
"""
Main method for CLI
- @param args: List[str] | None
+ @param args: List[str]
"""
start_time = time.time()
persistence_init()
args_dict = dict(vars(parser))
- for expected_arg in ["func", "debug", "no_paging"]:
+ for expected_arg in ["func", "debug", "no_pager"]:
args_dict.pop(expected_arg)
# Run function
# Otherwise print help
arg_parser.print_help()
- return 1, None
+ return 0, None
# Build the parser, set flags
_parser = parse_args()
# TODO: bug reporting?
# Try to run the function
- exit_code = None
+ exit_code = 1
try:
exit_code, *_results = func(_parser)
return exit_code
-Subproject commit bd445909c0e6165e82d6f077b3160cf2c07f4aa4
+Subproject commit 4f9eec211c1073f093411f15e29cb2347534e7cd
from ntclient import NUTRA_DIR
# TODO: init, handle when it doesn't exist yet
-# TODO: prompt to create profile if copying default `prefs.json` with PROFILE_ID: -1 (non-existent)
+# TODO: prompt to create profile if copying default `prefs.json` with PROFILE_ID: -1
+# (non-existent)
PREFS_FILE = os.path.join(NUTRA_DIR, "prefs.json")
PREFS = {}
PROFILE_ID = None
PROFILE_ID = PREFS.get("current_user")
if DEBUG and not PROFILE_ID:
print(
- "WARN: ~/.nutra/prefs.json doesn't contain valid PROFILE_ID, proceeding in bare mode"
+ "WARN: ~/.nutra/prefs.json doesn't contain valid PROFILE_ID,"
+ "proceeding in bare mode"
)
-"""Main SQL persistence module, need to rethink circular imports and shared code"""
+"""Main SQL persistence module, shared between USDA and NT databases"""
import sqlite3
-# FIXME: maybe just use separate methods for calls with vs. without headers
-# avoid the mypy headaches, and the liberal comments # type: ignore
-
+# ------------------------------------------------
+# Entry fetching methods
+# ------------------------------------------------
def sql_entries(sql_result: sqlite3.Cursor) -> list:
"""Formats and returns a `sql_result()` for console digestion and output"""
# TODO: return object: metadata, command, status, errors, etc?
return headers, rows
+# ------------------------------------------------
+# Supporting methods
+# ------------------------------------------------
def version(con: sqlite3.Connection) -> str:
"""Gets the latest entry from version table"""
con.close()
+# ------------------------------------------------
+# Main query methods
+# ------------------------------------------------
def _prep_query(
con: sqlite3.Connection, query: str, db_name: str, values=None
) -> tuple:
- """@param values: tuple | list | None"""
+ """@param values: tuple | list"""
from ntclient import DEBUG # pylint: disable=import-outside-toplevel
db_name: str,
values=None,
) -> list:
- """@param values: tuple | list | None"""
+ """@param values: tuple | list"""
cur, result = _prep_query(con, query, db_name, values)
db_name: str,
values=None,
) -> tuple:
- """@param values: tuple | list | None"""
+ """@param values: tuple | list"""
cur, result = _prep_query(con, query, db_name, values)
def sql_nt_next_index(table=None):
"""Used for previewing inserts"""
- query = "SELECT MAX(id) FROM %s;" % table # nosec: B608
- return int(sql(query)[0]["MAX(id)"])
+ query = "SELECT MAX(id) as max_id FROM %s;" % table # nosec: B608
+ return int(sql(query)[0]["max_id"])
################################################################################
name,
COUNT(recipe_id) AS n_foods,
SUM(grams) AS grams,
- created
+ recipe.created as created
FROM
- recipes
+ recipe
LEFT JOIN recipe_dat ON recipe_id = id
GROUP BY
id;
food_id,
grams
FROM
- recipes
+ recipe
INNER JOIN recipe_dat ON recipe_id = id
AND id = ?;
"""
if os.path.isfile(file_path):
# TODO: better logic than this
- recipe_id = extract_id_from_filename(file_path) or sql_nt_next_index("recipes")
+ recipe_id = extract_id_from_filename(file_path) or sql_nt_next_index("recipe")
print(recipe_id)
with open(file_path, encoding="utf-8") as file:
reader = csv.DictReader(file)
# Colors and buffer settings
################################################################################
+# TODO: make configurable in SQLite or prefs.json
+
THRESH_WARN = 0.7
COLOR_WARN = Fore.YELLOW
from ntclient import PY_MIN_STR, __author__, __email__, __title__, __version__
-# cd to parent dir of setup.py
-os.chdir(os.path.dirname(os.path.abspath(__file__)))
+os.chdir(os.path.dirname(os.path.realpath(__file__)))
+
+PLATFORM_SYSTEM = platform.system()
CLASSIFIERS = [
"Environment :: Console",
"Programming Language :: Unix Shell",
]
+# Read me
with open("README.rst", encoding="utf-8") as file:
README = file.read()
+# Requirements
with open("requirements.txt", encoding="utf-8") as file:
REQUIREMENTS = file.read().split()
-if platform.system() != "Windows":
- # python-Levenshtein builds natively on unix, requires vcvarsall.bat or vc++10 on Windows
+if PLATFORM_SYSTEM != "Windows":
+ # python-Levenshtein builds natively on Unix; Windows needs vcvarsall.bat or vc++10
with open("requirements-optional.txt", encoding="utf-8") as file:
optional_reqs = file.read().split()
REQUIREMENTS.extend(optional_reqs)
-setup(
- name=__title__,
- author=__author__,
- author_email=__email__,
- classifiers=CLASSIFIERS,
- install_requires=REQUIREMENTS,
- python_requires=">=%s" % PY_MIN_STR,
- zip_safe=False,
- packages=find_packages(exclude=["tests"]),
- include_package_data=True,
- platforms=["linux", "darwin", "win32"],
- scripts=glob.glob("scripts/*"),
- # entry_points={"console_scripts": ["nutra=ntclient.__main__:main"]},
- description="Home and office nutrient tracking software",
- long_description=README,
- long_description_content_type="text/x-rst",
- url="https://github.com/nutratech/cli",
- license="GPL v3",
- version=__version__,
-)
+# Prepare setup() inputs (OS dependent)
+kwargs = {
+ "name": __title__,
+ "author": __author__,
+ "author_email": __email__,
+ "classifiers": CLASSIFIERS,
+ "install_requires": REQUIREMENTS,
+ "python_requires": ">=%s" % PY_MIN_STR,
+ "zip_safe": False,
+ "packages": find_packages(exclude=["tests"]),
+ "include_package_data": True,
+ "platforms": ["linux", "darwin", "win32"],
+ "description": "Home and office nutrient tracking software",
+ "long_description": README,
+ "long_description_content_type": "text/x-rst",
+ "url": "https://github.com/nutratech/cli",
+ "license": "GPL v3",
+ "version": __version__,
+}
+
+if PLATFORM_SYSTEM == "Windows":
+ kwargs["entry_points"] = {
+ "console_scripts": ["nutra=ntclient.__main__:main", "n=ntclient.__main__:main"]
+ }
+else:
+ kwargs["scripts"] = glob.glob("scripts/*")
+
+# Setup method
+setup(**kwargs)
@author: shane
"""
+# pylint: disable=wrong-import-position
import os
import sys
from ntclient.services import init
from ntclient.utils.exceptions import SqlInvalidVersionError
+TEST_HOME = os.path.dirname(os.path.abspath(__file__))
+os.environ["NUTRA_HOME"] = os.path.join(TEST_HOME, ".nutra.test")
+
# TODO: integration tests.. create user, recipe, log.. analyze & compare
arg_parser = build_argparser()
-TEST_HOME = os.path.dirname(os.path.abspath(__file__))
def test_000_init():
set_flags(args)
assert args.debug is True
- assert args.no_paging is True
+ assert args.no_pager is True
from ntclient import DEBUG, PAGING # pylint: disable=import-outside-toplevel
sys.argv = ["./nutra"]
code = nt_main()
- assert code == 1
+ assert code == 0
with pytest.raises(SystemExit) as system_exit:
nt_main(args=["-h"])