Skip to main content

nutrients

The nutrient vocabulary and energy constant shared by the mealtime tools (pantry, recipes, eatout, plate), and by anything else that speaks the item format this package documents in FORMAT.md.

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); a tool that logs intake should refuse 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 a working Google Health client rather than invented: its payload builder for the split, and its nutrient-name parsing 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 a client 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.1

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.1
File Size Uploaded
mealtime_nutrients-0.3.1.tar.gz 16.3 kB Details

Built distribution (wheel)

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

Total release size: 29.5 kB

Release files / mealtime_nutrients-0.3.1.tar.gz

Download URL mealtime_nutrients-0.3.1.tar.gz
Size 16.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a67ea87f1cfbe6dcbfa203768cb7b098050a703aac59e092416d7cf1ae5ca040
BLAKE2b-256 checksum
How to use checksums
7f60e789590caeb782e41d512bc3008b838e88317e2eac81024f6ca0e960a063
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 27, 2026.

Transparency log

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

Download URL mealtime_nutrients-0.3.1-py3-none-any.whl
Size 13.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bcbc671a47d90caca653e6c0873958001c85a8c48caba8427142dc3d4c59935d
BLAKE2b-256 checksum
How to use checksums
fe64615019defdc3b286c7e01745600222760e792d7be7750e4b317e08c5b501
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 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

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