Skip to main content

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 → energy field, whose figure goes under a kcal key, not grams
  • carbs → totalCarbohydrate field
  • fat → totalFat field
  • fiber → DIETARY_FIBER enum 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 Decimal("4.184"), the thermochemical definition. It is a Decimal because that is a definition rather than a measurement, and the nearest float to 4.184 is really 4.18400000000000016.

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.

Both return a Decimal and accept a Decimal, int, str or float. A float is converted through str, so it reads back as the figure a label stated rather than the binary approximation stored for it. Callers still holding floats should wrap the result in float(), which marks where the lossy domain begins.

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.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mealtime-nutrients 0.3.0
File Size Uploaded
mealtime_nutrients-0.3.0.tar.gz 15.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mealtime-nutrients 0.3.0
File Interpreter ABI Platform
mealtime_nutrients-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.4 kB

Release files / mealtime_nutrients-0.3.0.tar.gz

Download URL mealtime_nutrients-0.3.0.tar.gz
Size 15.2 kB
Tags Source
SHA-256 checksum
How to use checksums
7c9cc510c26c18f6a89d02e7b20929c8e58fc600ace1c7f8b73630f874922a36
BLAKE2b-256 checksum
How to use checksums
e7e0a1559cd29f532700f377157d415ad3366af5de55b6e1661a0e54e0485406
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

Release files / mealtime_nutrients-0.3.0-py3-none-any.whl

Download URL mealtime_nutrients-0.3.0-py3-none-any.whl
Size 13.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
65984dcc080a443ebb4513e62ed4b328b265684c1eeb036b6f502bfb2821e634
BLAKE2b-256 checksum
How to use checksums
214dcc0fbd501390c98bebf584b3d7babf3b9c860a93f19feaebf1bbad3dcea3
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

Release history Release notifications | RSS feed

0.3.1

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page