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 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)

Source distribution for mealtime-nutrients 0.1.0
File Size Uploaded
mealtime_nutrients-0.1.0.tar.gz 13.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mealtime-nutrients 0.1.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

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