terpene_engineο
Terpene Engine β Cannabis phytochemistry modulation layer.
Loads terpene profiles and strain definitions from terpene_profiles.yaml, computes composite NCM deltas per strain, resolves entourage synergies, and provides the sativa/indica gradient interpolation used by the cascade engine for bipolar ENDOCANNABINOID_DRIFT staging.
# π₯ the stoner goddess gets her pharmacology right π
- class terpene_engine.TerpeneProfile(name, polarity, boiling_point_c, aroma, ncm_deltas, flavor_mods, effects)[source]ο
Bases:
objectA single cannabis terpene with its pharmacological and sensory properties.
Immutable record describing one aromatic terpene: its sativa/indica
polarity, the temperature at which it volatilises, an aroma blurb, the parsedncm_deltas(neurochemical-modulation shifts), a dict of 11D gustatoryflavor_mods, and a human-readable effects string. Instances are constructed byTerpeneEngine._ensure_loadedfrom theterpenessection ofterpene_profiles.yaml(thencm_deltasfield is produced by running each YAMLdeltastring throughparse_delta_string). They are looked up viaTerpeneEngine.get_terpeneand consumed byTerpeneEngine.compute_strain_effectwhen weighting a strain.- Parameters:
- class terpene_engine.StrainProfile(name, strain_gradient, classification, thc_pct, description, terpene_weights)[source]ο
Bases:
objectA cannabis strain described by its terpene composition and gradient.
Immutable record for one strain: its
strain_gradientposition on the indica-to-sativa axis (0.0-1.0), a coarseclassificationlabel, average THC percentage, a description, and aterpene_weightsmapping of terpene name to fractional weight. Instances are built byTerpeneEngine._ensure_loadedfrom thestrainssection ofterpene_profiles.yaml, retrieved byTerpeneEngine.get_strain, ranked byTerpeneEngine.find_strain_by_gradient, and read byTerpeneEngine.compute_strain_effectto drive the per-strain NCM math.- Parameters:
- class terpene_engine.StrainEffect(strain_name, strain_gradient, composite_deltas, entourage_bonuses, total_deltas, flavor_shifts, dominant_terpene, pole_label, active_entourage_rules)[source]ο
Bases:
objectThe fully computed pharmacological effect of a single cannabis strain.
Result bundle produced by
TerpeneEngine.compute_strain_effect: it carries the strain name and gradient alongside thecomposite_deltas(weighted sum of every terpeneβs NCM shifts), theentourage_bonusescontributed by fired synergy rules, the merged-and-saturatedtotal_deltas, the aggregate 11Dflavor_shifts, the dominant terpene, a sativa/indica/hybridpole_label, and the list of entourage rules that activated. This is a derived, read-mostly value object; itsto_dictmethod renders it for downstream consumers and serialisation.- Parameters:
- to_dict()[source]ο
Render this strain effect as a compact, rounded JSON-friendly dict.
Serialises the most useful fields of the
StrainEffectfor logging or transport: the strain name, the rounded gradient and pole label, the dominant terpene, the mergedtotal_deltasandflavor_shifts(each value rounded to keep the payload readable), and the names of the entourage rules that fired. Note thatcomposite_deltasandentourage_bonusesare intentionally omitted in favour of the already-mergedtotal_deltas. Pure transformation overselfwith no side effects. Invoked on instances returned byTerpeneEngine.compute_strain_effect; no other module imports this class in the repo yet.- Return type:
- Returns:
A dict with keys
strain,gradient,pole,dominant_terpene,deltas,flavor_shifts, andentourage_rules.
- class terpene_engine.TerpeneEngine(yaml_path=None)[source]ο
Bases:
objectCannabis phytochemistry computation engine.
Loads terpene profiles and strains from YAML, computes composite NCM effects, resolves entourage synergies, and provides the bipolar sativa/indica gradient for cascade interpolation.
- Parameters:
yaml_path (Optional[str])
- get_terpene(name)[source]ο
Look up a single terpene profile by name, case-insensitively.
Normalises the requested name to the upper-cased, underscore-joined key convention used in the loaded table and returns the matching
TerpeneProfile(orNonewhen absent). Triggers_ensure_loadedfirst so the YAML is hydrated on demand; otherwise it is a pure dict read with no side effects. Defined onTerpeneEngine, which is not yet imported elsewhere in the repo, so it is reached only via a constructed engine instance (the module is referenced by name in the output header thatscrape_leafly.pywrites, but is not yet imported by other code).- Parameters:
name (
str) β Terpene name; spaces are treated as underscores and case is ignored.- Return type:
- Returns:
The matching
TerpeneProfile, orNoneif no such terpene.
- get_strain(name)[source]ο
Look up a single strain profile by name, case- and separator-insensitively.
Normalises the requested name by upper-casing and folding both spaces and hyphens to underscores (so
"Blue Dream"and"blue-dream"resolve to the same key) and returns the matchingStrainProfileorNone. Calls_ensure_loadedto hydrate the YAML on first use; otherwise a pure dict read. Used internally bycompute_strain_effectto resolve the strain it is asked to compute, and otherwise reached via a constructedTerpeneEngineinstance since the module has no other importers in the repo yet.- Parameters:
name (
str) β Strain name; spaces and hyphens are folded to underscores and case is ignored.- Return type:
- Returns:
The matching
StrainProfile, orNoneif no such strain.
- list_terpenes()[source]ο
Return every loaded terpene name in sorted order.
Convenience accessor that hydrates the YAML via
_ensure_loadedand returns an alphabetically sorted list of the keys inself._terpenes, giving callers a quick catalogue of the available terpenes. Pure read with no side effects beyond the lazy load. Reached only through a constructedTerpeneEngineinstance, as the module is not imported elsewhere in the repo yet.
- list_strains()[source]ο
Return every loaded strain name, sorted by a stable string key.
Convenience accessor that hydrates the YAML via
_ensure_loadedand returns the keys ofself._strainssorted withstras the sort key, guarding against the case where the YAML loader coerces purely numeric strain names into ints (which would otherwise be unsortable against strings). Pure read apart from the lazy load. Reached only through a constructedTerpeneEngineinstance, as nothing else in the repo imports the module yet.
- compute_strain_effect(strain_name)[source]ο
Compute the full pharmacological effect of a cannabis strain.
Resolves terpene weights to composite NCM deltas, applies entourage synergy rules, computes flavor axis shifts, and determines the sativa/indica pole label.
- Parameters:
strain_name (
str) β Name of the strain to compute.- Return type:
- Returns:
StrainEffect dataclass or None if strain not found.
- compute_gradient_blend(gradient)[source]ο
Interpolate between sativa and indica NCM pole signatures.
Used by the cascade engine to lerp ENDOCANNABINOID_DRIFT stage deltas based on strain_gradient position.
- get_pole_info(pole)[source]ο
Return a copy of the raw pole definition for
sativaorindica.Hydrates the YAML via
_ensure_loadedand returns a shallow copy of the named poleβs entry fromself._poles(typically holding itsncm_signatureand related metadata), or an empty dict when the pole is absent. The copy keeps callers from mutating the engineβs loaded state. The samencm_signaturedata is consumed internally bycompute_gradient_blendto interpolate between poles. Reached only via a constructedTerpeneEngineinstance, as the module has no other importers in the repo yet.