nutrients
The nutrient vocabulary and energy constant shared by the mealtime tools (pantry, recipes, eatout, nutrilog, plate).
A data package. No parsing, no validation, no dependencies, and no domain logic — those belong in the tools that consume it.
Install
uv add mealtime-nutrients
Use
from mealtime_nutrients import API_FIELDS, API_NUTRIENTS, NUTRIENTS
"fiber" in NUTRIENTS # True — the wire name
API_NUTRIENTS["fiber"] # "DIETARY_FIBER" — where it goes in the API
API_FIELDS["carbs"] # "totalCarbohydrate" — a dedicated field
The vocabulary
NUTRIENTS holds the wire names: the 41 names that appear in the JSON
these tools exchange, per FORMAT.md. It is not Google Health's
API spelling, because the two disagree — the format says kcal, fat, carbs
and fiber where the API says energy, totalFat, CARBOHYDRATES and
DIETARY_FIBER. A consumer that imported the API names would still need its
own wire list plus a translation layer.
CORE_NUTRIENTS is the four every tool treats as required (kcal, protein,
fat, carbs); nutrilog refuses a new entry without them.
Every nutrient is measured in grams. Google Health accepts no milligram or
microgram variant, not even for the trace minerals and vitamins whose labels
print mg or µg, so a record holding milligrams holds a figure a thousand times
too large. ENERGY_NUTRIENT (kcal) is the sole exception and is
kilocalories.
The mapping
Google Health's nutrition log has two places to put a figure, so the mapping has two halves:
| wire → destination | goes to | |
|---|---|---|
API_NUTRIENTS |
saturated_fat → SATURATED_FAT |
the nutrients array |
API_FIELDS |
carbs → totalCarbohydrate |
a dedicated log object |
Membership in API_NUTRIENTS is what "array-eligible" means. The mapping is
total (every wire name resolves), injective (no two names collide on one
destination), and surjective onto NUTRIENT_TYPES minus one documented
exception. Tests pin all three, and there is exactly one wire name per
nutrient — a second spelling would let one item declare the same figure twice.
Only four names are not a plain lowercasing of their destination:
kcal→energyfield, whose figure goes under akcalkey, notgramscarbs→totalCarbohydratefieldfat→totalFatfieldfiber→DIETARY_FIBERenum member
And one that is, but still surprises: protein → PROTEIN, a core macro that
nonetheless travels in the array unlike the other three. That asymmetry is
real, and comes from MealLog.to_api_payload.
The routing was read off nutrilog, not invented — MealLog.to_api_payload for
the split, cli.STANDARD_NUTRIENTS and NutrientType.from_string for the
non-identity spellings.
The one unreachable nutrient
UNREACHABLE_NUTRIENT_TYPES is {"CARBOHYDRATES"}: the only enum member with
no wire name. carbs already carries carbohydrate to the dedicated
totalCarbohydrate field, and nutrilog matches the core four before consulting
the enum, so accepting carbohydrates as a second wire name would let one item
send 25 g to totalCarbohydrate and another 25 g to the nutrients array
— carbohydrate declared twice in one log. An unreachable member is the lesser
problem, because carbs still logs the nutrient.
fat and kcal cannot collide this way: Google Health publishes no total-fat
and no energy member. A test pins that, so a future enum addition cannot
silently reintroduce the double declaration.
The fat breakdowns are not this case and should not be "fixed" by symmetry.
SATURATED_FAT and its neighbours are subtypes of the totalFat field rather
than duplicates of it, and the overlap among them — unsaturated_fat covers
the same grams as monounsaturated_fat plus polyunsaturated_fat — is Google
Health's own, with real labels stating any of the three. All five stay
reachable.
Energy
KJ_PER_KCAL is 4.184, the thermochemical definition. Use kcal_from_kj and
kj_from_kcal so the direction is unambiguous at the call site; do not
multiply by a rounded reciprocal such as 0.239006, which disagrees with
1 / 4.184 in the 7th significant figure.
nutrients.json
plate is JavaScript and cannot import a Python module, so the vocabulary and
the mapping are also committed as nutrients.json. Regenerate after editing
the vocabulary:
uv run python -m mealtime_nutrients.generate_json
A test fails if the committed file and the generator disagree.
Develop
uv run pytest
uv run ruff check src
Release files for mealtime-nutrients 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mealtime_nutrients-0.1.0.tar.gz | 13.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mealtime_nutrients-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.6 kB
Release files / mealtime_nutrients-0.1.0.tar.gz
| Download URL | mealtime_nutrients-0.1.0.tar.gz |
|---|---|
| Size | 13.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bc080c56ca8a7fe1310fec89807c259214e79f4b6359f8a72764811c0a1b602a
|
|
BLAKE2b-256 checksum How to use checksums |
3ceb21a5a495ce2e8f44ebc3dbba4ba6349315bd0ed42779f335b15216051bf8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logRelease files / mealtime_nutrients-0.1.0-py3-none-any.whl
| Download URL | mealtime_nutrients-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
842eb381752b7626add6acb7308f187413d2bbd4e10c8a63afc646d2e0922ffd
|
|
BLAKE2b-256 checksum How to use checksums |
819aed15c52be7dff235c12b575f0356518090d719e2dd6c68252d71526debbe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency log