dotpromptz-handlebars 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ *$py.class
2
+ *.egg
3
+ *.egg-info/
4
+ *.py[cod]
5
+ *.so
6
+ .DS_Store
7
+ .Python
8
+ .cache/
9
+ .coverage
10
+ .eggs/
11
+ .genkit
12
+ .idea/
13
+ .installed.cfg
14
+ .mypy_cache/
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .venv
18
+ ENV/
19
+ __pycache__/
20
+ build/
21
+ develop-eggs/
22
+ dist/
23
+ downloads/
24
+ eggs/
25
+ lib/
26
+ lib64/
27
+ parts/
28
+ sdist/
29
+ site/
30
+ var/
31
+ venv/
32
+ wheels/
@@ -0,0 +1,25 @@
1
+ # Copyright 2026 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ # SPDX-License-Identifier: Apache-2.0
16
+
17
+ load("@rules_python//python:defs.bzl", "py_library")
18
+
19
+ package(default_visibility = ["//visibility:public"])
20
+
21
+ py_library(
22
+ name = "handlebars",
23
+ srcs = glob(["dotpromptz_handlebars/**/*.py"]),
24
+ imports = ["."],
25
+ )
@@ -0,0 +1,157 @@
1
+ # Changelog
2
+
3
+ ## [0.2.0](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.10...dotpromptz-handlebars-0.2.0) (2026-10-05)
4
+
5
+ ### ⚠ BREAKING CHANGES
6
+
7
+ * **imports:** Python import module is now `dotpromptz_handlebars`, replacing `handlebarrz` (`import handlebarrz` -> `import dotpromptz_handlebars`).
8
+
9
+ ### Features
10
+
11
+ * **engine:** rewrite Handlebars template engine in pure Python with zero native dependencies ([#620](https://github.com/google/dotprompt/pull/620)).
12
+ * **helpers:** `options.fn([context])` and `options.inverse([context])` accept an optional context argument to render block bodies with explicit scope, matching Handlebars.js.
13
+ * **helpers:** `HelperOptions.context` provides direct attribute access to the active scope, while maintaining `options.context()` callable compatibility for dictionary scopes.
14
+
15
+ ## [0.1.9](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.8...dotpromptz-handlebars-0.1.9) (2026-09-18)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * add Apache-2.0 license metadata to all packages ([#528](https://github.com/google/dotprompt/issues/528)) ([c76c663](https://github.com/google/dotprompt/commit/c76c6639fb77b39ef5b45a1a8dbebacc4c9bd422))
21
+ * **python:** expire helper options on return and pass through helper exits in render_template ([#607](https://github.com/google/dotprompt/issues/607)) ([df61290](https://github.com/google/dotprompt/commit/df612903a8777ce626b926f5c840c6d4758874f1))
22
+ * **python:** isolate runtime context from input and reject cyclic partials ([#604](https://github.com/google/dotprompt/issues/604)) ([6b97598](https://github.com/google/dotprompt/commit/6b97598cb33bf9433ae7ad6cff63ced15299de0d))
23
+
24
+ ## [0.1.8](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.7...dotpromptz-handlebars-0.1.8) (2026-01-30)
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * **docs:** remove incorrect OpenSSF Best Practices badge ([#490](https://github.com/google/dotprompt/issues/490)) ([6cdabd7](https://github.com/google/dotprompt/commit/6cdabd7e4d09e5b71034d0bae183af4cfc94fe1d))
30
+
31
+
32
+ ### Documentation
33
+
34
+ * **dotpromptz-handlebars:** improve PyPI package description ([#487](https://github.com/google/dotprompt/issues/487)) ([b693e6c](https://github.com/google/dotprompt/commit/b693e6c52b19ba746b505c30a705419281e4d8ce))
35
+
36
+ ## [0.1.7](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.6...dotpromptz-handlebars-0.1.7) (2026-01-30)
37
+
38
+
39
+ ### Bug Fixes
40
+
41
+ * **ci:** auto-update lockfiles and label release PRs ([#483](https://github.com/google/dotprompt/issues/483)) ([3ae17e4](https://github.com/google/dotprompt/commit/3ae17e44b9acbd4efe5aab53b30a5c81694cbe4e))
42
+
43
+ ## [0.1.6](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.5...dotpromptz-handlebars-0.1.6) (2026-01-30)
44
+
45
+
46
+ ### Bug Fixes
47
+
48
+ * **handlebarrz:** add toggleable platform flags and Unicode tests ([#481](https://github.com/google/dotprompt/issues/481)) ([7130b4c](https://github.com/google/dotprompt/commit/7130b4ce172bf70513d55417f6bcc309511d83f0))
49
+
50
+ ## [0.1.5](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.4...dotpromptz-handlebars-0.1.5) (2026-01-30)
51
+
52
+
53
+ ### Bug Fixes
54
+
55
+ * **ci:** add RUSTUP_MAX_RETRIES and use native ARM64 runners ([#479](https://github.com/google/dotprompt/issues/479)) ([aefd33a](https://github.com/google/dotprompt/commit/aefd33a7a595ae4fc31a7f1b1f28692d7addc046))
56
+
57
+ ## [0.1.4](https://github.com/google/dotprompt/compare/dotpromptz-handlebars-0.1.3...dotpromptz-handlebars-0.1.4) (2026-01-30)
58
+
59
+
60
+ ### Features
61
+
62
+ * **dotpromptz-handlebars:** add package_name function for smoke testing ([#457](https://github.com/google/dotprompt/issues/457)) ([681cc52](https://github.com/google/dotprompt/commit/681cc527dfd2d534ba5e0b6b2d73c52ead267b59))
63
+ * **py:** add bazel build/test support and automate requirements ([#399](https://github.com/google/dotprompt/issues/399)) ([efd7fe0](https://github.com/google/dotprompt/commit/efd7fe0592e2491c34e8fd399e756de375c802eb))
64
+ * **py:** switch to using ty for type checking ([#376](https://github.com/google/dotprompt/issues/376)) ([7f1c026](https://github.com/google/dotprompt/commit/7f1c0268e5de5a2d6d887ac590d110dea7d3ed07))
65
+
66
+
67
+ ### Bug Fixes
68
+
69
+ * **dotpromptz-handlebars:** version mismatch in handlebarrz ([#428](https://github.com/google/dotprompt/issues/428)) ([1cf8e01](https://github.com/google/dotprompt/commit/1cf8e019a1c4b94254c5819ceb312df2b8c1e889))
70
+ * **handlebarrz:** correct register_helper type stub signature ([#434](https://github.com/google/dotprompt/issues/434)) ([7bc7e2a](https://github.com/google/dotprompt/commit/7bc7e2a72f792940481fdf180961c7508b3ae389))
71
+ * update package name references to dotpromptz-handlebars ([#403](https://github.com/google/dotprompt/issues/403)) ([8bbd99d](https://github.com/google/dotprompt/commit/8bbd99debe511a5b7327d80aeb40b6a854d57630)), closes [#344](https://github.com/google/dotprompt/issues/344)
72
+
73
+ ## [0.1.3](https://github.com/google/dotprompt/compare/handlebarrz-0.1.2...handlebarrz-0.1.3) (2025-12-12)
74
+
75
+
76
+ ### Features
77
+
78
+ * **py:** add support for python 3.14 ([#365](https://github.com/google/dotprompt/issues/365)) ([53db722](https://github.com/google/dotprompt/commit/53db722352d360c9097028d63eb1b7e9576d3d24))
79
+
80
+
81
+ ### Bug Fixes
82
+
83
+ * **py/handlebarrz:** remove redundant lock file ([#360](https://github.com/google/dotprompt/issues/360)) ([db5416a](https://github.com/google/dotprompt/commit/db5416a4f7ce508a3d684b7c56ea8a50f46ee65d))
84
+
85
+ ## [0.1.2](https://github.com/google/dotprompt/compare/handlebarrz-0.1.1...handlebarrz-0.1.2) (2025-11-13)
86
+
87
+
88
+ ### Features
89
+
90
+ * cargo workspace configuration and bazel build files for hermetic environment ([#257](https://github.com/google/dotprompt/issues/257)) ([aef822e](https://github.com/google/dotprompt/commit/aef822ed484d256ba95a3544e132a9b33e0dc02d))
91
+ * **handlebarrz:** CI to publish rust python package ([#152](https://github.com/google/dotprompt/issues/152)) ([20765d8](https://github.com/google/dotprompt/commit/20765d83c50537cf935fe461a24f5c86d970d787))
92
+ * **handlebarrz:** native ifEquals, unlessEquals, and json helpers ([#121](https://github.com/google/dotprompt/issues/121)) ([e3619e9](https://github.com/google/dotprompt/commit/e3619e906cd0b69d854ca50d798e36cf44c130bd))
93
+ * partial test runner implementation now loads tests ([#139](https://github.com/google/dotprompt/issues/139)) ([b09dd2f](https://github.com/google/dotprompt/commit/b09dd2f9b8029317ce484d6f32d5a3fb89f5f7e1))
94
+ * **py/dotprompt:** render and compile implementations ([#263](https://github.com/google/dotprompt/issues/263)) ([961d0db](https://github.com/google/dotprompt/commit/961d0dbbd9c2ce522252bc3d92f6dde4b7fe9cc1))
95
+ * **py/dotpromptz:** add initial Dotprompt._resolve_partials implementation ([#215](https://github.com/google/dotprompt/issues/215)) ([03a161c](https://github.com/google/dotprompt/commit/03a161c3440a680bc0df472f35efa155fe0d5151))
96
+ * **py/dotpromptz:** configure handlebars to not escape by default ([#163](https://github.com/google/dotprompt/issues/163)) ([f7c33e1](https://github.com/google/dotprompt/commit/f7c33e1303476fd473e803f930ac1e1f9e1d87c9))
97
+ * **py/dotpromptz:** construct test-specific dotprompt instance with partials and partial resolver set up ([#275](https://github.com/google/dotprompt/issues/275)) ([0af9a64](https://github.com/google/dotprompt/commit/0af9a64acf50278bdffda337e19c66fbb97e43a3))
98
+ * **py/dotpromptz:** implement helpers in terms of the rust implementation of handlebars-rust and fix go flakiness ([#115](https://github.com/google/dotprompt/issues/115)) ([314c0b5](https://github.com/google/dotprompt/commit/314c0b5182aaad25bf4cfccb8207faa60f63256f))
99
+ * **py/dotpromptz:** initial bits of Dotprompt class ([#148](https://github.com/google/dotprompt/issues/148)) ([90f7838](https://github.com/google/dotprompt/commit/90f78384a958d41d78dee48497a78dfde11f4476))
100
+ * **py/handlebarrz:** add a Template.compile method to the Python wrapper to make it easier to port the JS implementation ([#201](https://github.com/google/dotprompt/issues/201)) ([9295972](https://github.com/google/dotprompt/commit/92959720fbf2e8ee410d5b8c0c174c6ef464e667))
101
+ * **py/handlebarrz:** Python bindings for handlebars-rust ([#113](https://github.com/google/dotprompt/issues/113)) ([6b6a97e](https://github.com/google/dotprompt/commit/6b6a97e01acc49f53586eb5b8b2b410ae82ce6ce))
102
+ * **py:** local variables support workaround ([#318](https://github.com/google/dotprompt/issues/318)) ([d09598b](https://github.com/google/dotprompt/commit/d09598b969d5dbeaed3ca4136e903b4a2dc80531))
103
+ * python implementations of helpers ([#129](https://github.com/google/dotprompt/issues/129)) ([79c6ef3](https://github.com/google/dotprompt/commit/79c6ef3e9cc472fed3a832c00a1515ceef0981da))
104
+ * **python:** support lower versions of python (>=3.10) ([#187](https://github.com/google/dotprompt/issues/187)) ([4240f9d](https://github.com/google/dotprompt/commit/4240f9d720891e350f9116aa4401ce6ea7fac5a3))
105
+ * use the HEAD version of addlicense ([#280](https://github.com/google/dotprompt/issues/280)) ([bdf0d36](https://github.com/google/dotprompt/commit/bdf0d36a430a363de4163f48394546cba884eaaf))
106
+ * use the more maintained YAML parsing lib at https://github.com/goccy/go-yaml ([#151](https://github.com/google/dotprompt/issues/151)) ([910b3a7](https://github.com/google/dotprompt/commit/910b3a72f3756296c3b01b96936a5bc4c9fa88ef))
107
+
108
+
109
+ ### Bug Fixes
110
+
111
+ * change project name for pypi publish ([#200](https://github.com/google/dotprompt/issues/200)) ([2c07132](https://github.com/google/dotprompt/commit/2c0713264fb2c30bdc43f1bd9e51d416f96d1b7e))
112
+ * **docs:** update docs for handlebarrz ([#116](https://github.com/google/dotprompt/issues/116)) ([ce643b1](https://github.com/google/dotprompt/commit/ce643b1f5299ba2a6b214fb57965980d412c1a7b))
113
+ * **handlebarrz:** Compatibility tests for python 3.10 ([#190](https://github.com/google/dotprompt/issues/190)) ([e459e9c](https://github.com/google/dotprompt/commit/e459e9ce94f76d42615593987f99221b0f55a0d3))
114
+ * **license:** add license header to stub types file ([#144](https://github.com/google/dotprompt/issues/144)) ([0abd498](https://github.com/google/dotprompt/commit/0abd49848548f2148a37ec686d703126d8fe8504))
115
+ * **license:** use the full license header in rust source, script files and yaml spec files ([#143](https://github.com/google/dotprompt/issues/143)) ([77ccec9](https://github.com/google/dotprompt/commit/77ccec93a4bf5ccd65932a701676554866e68c6f))
116
+ * **license:** use the full license header in source code ([#142](https://github.com/google/dotprompt/issues/142)) ([64894ef](https://github.com/google/dotprompt/commit/64894ef898876b861c6c244d522f634cd8fcc842))
117
+ * **py/dotpromptz:** address compatibility with python 3.10 and add tox configuration for parallelized tests ([#188](https://github.com/google/dotprompt/issues/188)) ([d2ba21f](https://github.com/google/dotprompt/commit/d2ba21ff3e54f4ca4328b7e574bb6492699095bc))
118
+ * **py/handlebarrz:** helpers support in handlebarrz ([#291](https://github.com/google/dotprompt/issues/291)) ([d5d66a3](https://github.com/google/dotprompt/commit/d5d66a35858a068c2995b82fe54b62f0be4d057f))
119
+ * **scripts:** do not allow running scripts as root; prevent accidental mishaps; update rust checks ([#259](https://github.com/google/dotprompt/issues/259)) ([5cc067d](https://github.com/google/dotprompt/commit/5cc067dc44eaacab2e2dfa387bc79aa3f23d62c8))
120
+ * some lint in the rust code ([#250](https://github.com/google/dotprompt/issues/250)) ([3ef3dd8](https://github.com/google/dotprompt/commit/3ef3dd8ed98c0f5402b22fdba0e852074d2923e7))
121
+
122
+ ## [0.1.1](https://github.com/google/dotprompt/compare/handlebarrz-v0.1.0...handlebarrz-0.1.1) (2025-10-24)
123
+
124
+
125
+ ### Features
126
+
127
+ * cargo workspace configuration and bazel build files for hermetic environment ([#257](https://github.com/google/dotprompt/issues/257)) ([aef822e](https://github.com/google/dotprompt/commit/aef822ed484d256ba95a3544e132a9b33e0dc02d))
128
+ * **handlebarrz:** CI to publish rust python package ([#152](https://github.com/google/dotprompt/issues/152)) ([20765d8](https://github.com/google/dotprompt/commit/20765d83c50537cf935fe461a24f5c86d970d787))
129
+ * **handlebarrz:** native ifEquals, unlessEquals, and json helpers ([#121](https://github.com/google/dotprompt/issues/121)) ([e3619e9](https://github.com/google/dotprompt/commit/e3619e906cd0b69d854ca50d798e36cf44c130bd))
130
+ * partial test runner implementation now loads tests ([#139](https://github.com/google/dotprompt/issues/139)) ([b09dd2f](https://github.com/google/dotprompt/commit/b09dd2f9b8029317ce484d6f32d5a3fb89f5f7e1))
131
+ * **py/dotprompt:** render and compile implementations ([#263](https://github.com/google/dotprompt/issues/263)) ([961d0db](https://github.com/google/dotprompt/commit/961d0dbbd9c2ce522252bc3d92f6dde4b7fe9cc1))
132
+ * **py/dotpromptz:** add initial Dotprompt._resolve_partials implementation ([#215](https://github.com/google/dotprompt/issues/215)) ([03a161c](https://github.com/google/dotprompt/commit/03a161c3440a680bc0df472f35efa155fe0d5151))
133
+ * **py/dotpromptz:** configure handlebars to not escape by default ([#163](https://github.com/google/dotprompt/issues/163)) ([f7c33e1](https://github.com/google/dotprompt/commit/f7c33e1303476fd473e803f930ac1e1f9e1d87c9))
134
+ * **py/dotpromptz:** construct test-specific dotprompt instance with partials and partial resolver set up ([#275](https://github.com/google/dotprompt/issues/275)) ([0af9a64](https://github.com/google/dotprompt/commit/0af9a64acf50278bdffda337e19c66fbb97e43a3))
135
+ * **py/dotpromptz:** implement helpers in terms of the rust implementation of handlebars-rust and fix go flakiness ([#115](https://github.com/google/dotprompt/issues/115)) ([314c0b5](https://github.com/google/dotprompt/commit/314c0b5182aaad25bf4cfccb8207faa60f63256f))
136
+ * **py/dotpromptz:** initial bits of Dotprompt class ([#148](https://github.com/google/dotprompt/issues/148)) ([90f7838](https://github.com/google/dotprompt/commit/90f78384a958d41d78dee48497a78dfde11f4476))
137
+ * **py/handlebarrz:** add a Template.compile method to the Python wrapper to make it easier to port the JS implementation ([#201](https://github.com/google/dotprompt/issues/201)) ([9295972](https://github.com/google/dotprompt/commit/92959720fbf2e8ee410d5b8c0c174c6ef464e667))
138
+ * **py/handlebarrz:** Python bindings for handlebars-rust ([#113](https://github.com/google/dotprompt/issues/113)) ([6b6a97e](https://github.com/google/dotprompt/commit/6b6a97e01acc49f53586eb5b8b2b410ae82ce6ce))
139
+ * **py:** local variables support workaround ([#318](https://github.com/google/dotprompt/issues/318)) ([d09598b](https://github.com/google/dotprompt/commit/d09598b969d5dbeaed3ca4136e903b4a2dc80531))
140
+ * python implementations of helpers ([#129](https://github.com/google/dotprompt/issues/129)) ([79c6ef3](https://github.com/google/dotprompt/commit/79c6ef3e9cc472fed3a832c00a1515ceef0981da))
141
+ * **python:** support lower versions of python (>=3.10) ([#187](https://github.com/google/dotprompt/issues/187)) ([4240f9d](https://github.com/google/dotprompt/commit/4240f9d720891e350f9116aa4401ce6ea7fac5a3))
142
+ * use the HEAD version of addlicense ([#280](https://github.com/google/dotprompt/issues/280)) ([bdf0d36](https://github.com/google/dotprompt/commit/bdf0d36a430a363de4163f48394546cba884eaaf))
143
+ * use the more maintained YAML parsing lib at https://github.com/goccy/go-yaml ([#151](https://github.com/google/dotprompt/issues/151)) ([910b3a7](https://github.com/google/dotprompt/commit/910b3a72f3756296c3b01b96936a5bc4c9fa88ef))
144
+
145
+
146
+ ### Bug Fixes
147
+
148
+ * change project name for pypi publish ([#200](https://github.com/google/dotprompt/issues/200)) ([2c07132](https://github.com/google/dotprompt/commit/2c0713264fb2c30bdc43f1bd9e51d416f96d1b7e))
149
+ * **docs:** update docs for handlebarrz ([#116](https://github.com/google/dotprompt/issues/116)) ([ce643b1](https://github.com/google/dotprompt/commit/ce643b1f5299ba2a6b214fb57965980d412c1a7b))
150
+ * **handlebarrz:** Compatibility tests for python 3.10 ([#190](https://github.com/google/dotprompt/issues/190)) ([e459e9c](https://github.com/google/dotprompt/commit/e459e9ce94f76d42615593987f99221b0f55a0d3))
151
+ * **license:** add license header to stub types file ([#144](https://github.com/google/dotprompt/issues/144)) ([0abd498](https://github.com/google/dotprompt/commit/0abd49848548f2148a37ec686d703126d8fe8504))
152
+ * **license:** use the full license header in rust source, script files and yaml spec files ([#143](https://github.com/google/dotprompt/issues/143)) ([77ccec9](https://github.com/google/dotprompt/commit/77ccec93a4bf5ccd65932a701676554866e68c6f))
153
+ * **license:** use the full license header in source code ([#142](https://github.com/google/dotprompt/issues/142)) ([64894ef](https://github.com/google/dotprompt/commit/64894ef898876b861c6c244d522f634cd8fcc842))
154
+ * **py/dotpromptz:** address compatibility with python 3.10 and add tox configuration for parallelized tests ([#188](https://github.com/google/dotprompt/issues/188)) ([d2ba21f](https://github.com/google/dotprompt/commit/d2ba21ff3e54f4ca4328b7e574bb6492699095bc))
155
+ * **py/handlebarrz:** helpers support in handlebarrz ([#291](https://github.com/google/dotprompt/issues/291)) ([d5d66a3](https://github.com/google/dotprompt/commit/d5d66a35858a068c2995b82fe54b62f0be4d057f))
156
+ * **scripts:** do not allow running scripts as root; prevent accidental mishaps; update rust checks ([#259](https://github.com/google/dotprompt/issues/259)) ([5cc067d](https://github.com/google/dotprompt/commit/5cc067dc44eaacab2e2dfa387bc79aa3f23d62c8))
157
+ * some lint in the rust code ([#250](https://github.com/google/dotprompt/issues/250)) ([3ef3dd8](https://github.com/google/dotprompt/commit/3ef3dd8ed98c0f5402b22fdba0e852074d2923e7))
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.5
2
+ Name: dotpromptz-handlebars
3
+ Version: 0.2.0
4
+ Summary: A pure Python implementation of the Handlebars template engine.
5
+ Author: Google
6
+ License-Expression: Apache-2.0
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Text Processing :: Markup
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+
21
+ # dotpromptz-handlebars
22
+
23
+ A pure-Python Handlebars implementation, owned by the Genkit team. It implements the subset of Handlebars that [Dotprompt](https://github.com/google/dotprompt) templates use, not the full language.
24
+
25
+ Dotprompt is language-agnostic. A `.prompt` file should render the same way in every SDK, so what a prompt does is defined by the file, not by the language running it. To keep that true, this package treats Handlebars.js 4.7.9 as the spec. Handlebars has no standalone spec. Handlebars.js is the reference implementation that the other ports follow, so where implementations disagree, Handlebars.js wins. 4.7.9 is the latest Handlebars.js release, and it's what the Dotprompt JS SDK's `^4.7.8` range resolves to on a fresh install. Conformance tests check this package's output against it.
26
+
27
+ No Rust or Node at runtime.
28
+
29
+ ```
30
+ uv add dotpromptz-handlebars
31
+ ```
32
+
33
+ ## Quick start
34
+
35
+ ```python
36
+ from dotpromptz_handlebars import Handlebars
37
+
38
+ # 1. Compile once
39
+ hb = Handlebars()
40
+ render = hb.compile(
41
+ 'Table for {{party}}. '
42
+ '{{#if allergies}}Avoid: {{#each allergies}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}.{{/if}}'
43
+ )
44
+
45
+ # 2. Render many times
46
+ print(render({'party': 4, 'allergies': ['peanuts', 'shellfish']}))
47
+ # => Table for 4. Avoid: peanuts, shellfish.
48
+
49
+ print(render({'party': 2, 'allergies': []}))
50
+ # => Table for 2.
51
+ ```
52
+
53
+ `compile()` returns a function. Call it with your input dict. Pass `data=` for values the template reads with `@`:
54
+
55
+ ```python
56
+ render = hb.compile('{{name}} / {{@request_id}}')
57
+ print(render({'name': 'Ana'}, data={'request_id': 'r-42'}))
58
+ # => Ana / r-42
59
+ ```
60
+
61
+ ## Helpers
62
+
63
+ A helper is `fn(args, options)`. `args` holds the positional arguments and `options.hash` holds the `key=value` ones.
64
+
65
+ ```python
66
+ def price(args, options):
67
+ cents = args[0]
68
+ currency = options.hash.get('currency', 'USD')
69
+ return f'{cents / 100:.2f} {currency}'
70
+
71
+
72
+ hb.register_helper('price', price)
73
+ print(hb.compile('Salmon: {{price cents currency="EUR"}}')({'cents': 1850}))
74
+ # => Salmon: 18.50 EUR
75
+ ```
76
+
77
+ For a block helper (`{{#name}}...{{/name}}`), `options.fn(context)` renders the body and `options.inverse(context)` renders the `{{else}}` body:
78
+
79
+ ```python
80
+ def loud(args, options):
81
+ return options.fn(options.context).upper()
82
+
83
+
84
+ hb.register_helper('loud', loud)
85
+ print(hb.compile('{{#loud}}chef says {{dish}}{{/loud}}')({'dish': 'tartine'}))
86
+ # => CHEF SAYS TARTINE
87
+ ```
88
+
89
+ `options.context` holds the current scope. For backward compatibility with `handlebarrz`, calling `options.context()` returns the dictionary.
90
+
91
+ Helper output gets escaped like any other value. Return a `SafeString` to insert markup as written. Escaping is then up to you.
92
+
93
+ `if`, `unless`, `each`, `with`, `lookup`, and `log` are built in. You can't override them with `register_helper`.
94
+
95
+ ## Partials
96
+
97
+ ```python
98
+ hb.register_partial('dish', '- {{name}} ({{price}})\n')
99
+ render = hb.compile('Menu:\n{{#each dishes}}{{> dish}}{{/each}}')
100
+ print(render({'dishes': [{'name': 'Tartine', 'price': 14}, {'name': 'Soup', 'price': 9}]}))
101
+ # => Menu:
102
+ # - Tartine (14)
103
+ # - Soup (9)
104
+ ```
105
+
106
+ A missing partial raises. `{{#> name}}fallback{{/name}}` renders the fallback instead. Inline partials (`{{#*inline "name"}}`) and dynamic partials (`{{> (helperName)}}`) work too.
107
+
108
+ ## Escaping
109
+
110
+ `{{value}}` HTML-escapes by default. `{{{value}}}` doesn't.
111
+
112
+ ```python
113
+ render = Handlebars().compile('{{note}} | {{{note}}}')
114
+ print(render({'note': 'Fish & <b>Chips</b>'}))
115
+ # => Fish &amp; &lt;b&gt;Chips&lt;/b&gt; | Fish & <b>Chips</b>
116
+ ```
117
+
118
+ Prompts usually go to a model, not a browser. To turn escaping off everywhere, use `Handlebars(escape_html=False)`.
119
+
120
+ ## Strict mode
121
+
122
+ `Handlebars(strict=True)` raises when the template prints a path that isn't in the input:
123
+
124
+ ```python
125
+ from dotpromptz_handlebars import Handlebars, StrictModeError
126
+
127
+ try:
128
+ Handlebars(strict=True).compile('Hello {{user.name}}')({'user': {}})
129
+ except StrictModeError as err:
130
+ print(err.path)
131
+ # => user.name
132
+ ```
133
+
134
+ Conditions don't raise. `{{#if user.name}}` on a missing path takes the else branch.
135
+
136
+ ## Values that surprise Python developers
137
+
138
+ Dotprompt defines what a template means, independent of the language that renders it. Dotprompt templates use Handlebars semantics, and this package takes them from Handlebars.js 4.7.9. Conditionals and printed values follow those semantics, not Python's `bool()` or `str()`:
139
+
140
+ - `0` fails `{{#if}}` but enters `{{#with}}`. Use `{{#if n includeZero=true}}` to keep `0`.
141
+ - `{}` enters `{{#if}}`. `{{#if}}` takes the else branch only for a missing key, `None`, `False`, `""`, `0`, or `[]`.
142
+ - Lists print as `1,2` and dicts print as `[object Object]`. Format structured data with a helper. Dotprompt ships `{{json value}}` for this.
143
+ - `1.0` prints as `1`, and `False` prints as `false`.
144
+
145
+ ## What's not supported
146
+
147
+ These raise `ValueError`:
148
+
149
+ - Decorators (`{{* name}}`).
150
+ - Functions in the input dict. Register them with `register_helper`, so a template can only call code you chose.
151
+ - Broken templates. Which templates fail matches Handlebars.js, but the error messages are worded differently.
152
+
153
+ Everything else a prompt uses is supported:
154
+ - **Paths:** `user.name`, `../name`, `items.[0]`
155
+ - **Blocks:** `if`, `unless`, `each`, `with`, with `else` and `else if`
156
+ - **Block parameters:** `as |item index|`
157
+ - **Data:** `@index`, `@key`, `@first`, `@last`, `@root`
158
+ - **Syntax:** subexpressions, comments, `~` whitespace control, and raw blocks (`{{{{raw}}}}`)
@@ -0,0 +1,138 @@
1
+ # dotpromptz-handlebars
2
+
3
+ A pure-Python Handlebars implementation, owned by the Genkit team. It implements the subset of Handlebars that [Dotprompt](https://github.com/google/dotprompt) templates use, not the full language.
4
+
5
+ Dotprompt is language-agnostic. A `.prompt` file should render the same way in every SDK, so what a prompt does is defined by the file, not by the language running it. To keep that true, this package treats Handlebars.js 4.7.9 as the spec. Handlebars has no standalone spec. Handlebars.js is the reference implementation that the other ports follow, so where implementations disagree, Handlebars.js wins. 4.7.9 is the latest Handlebars.js release, and it's what the Dotprompt JS SDK's `^4.7.8` range resolves to on a fresh install. Conformance tests check this package's output against it.
6
+
7
+ No Rust or Node at runtime.
8
+
9
+ ```
10
+ uv add dotpromptz-handlebars
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```python
16
+ from dotpromptz_handlebars import Handlebars
17
+
18
+ # 1. Compile once
19
+ hb = Handlebars()
20
+ render = hb.compile(
21
+ 'Table for {{party}}. '
22
+ '{{#if allergies}}Avoid: {{#each allergies}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}.{{/if}}'
23
+ )
24
+
25
+ # 2. Render many times
26
+ print(render({'party': 4, 'allergies': ['peanuts', 'shellfish']}))
27
+ # => Table for 4. Avoid: peanuts, shellfish.
28
+
29
+ print(render({'party': 2, 'allergies': []}))
30
+ # => Table for 2.
31
+ ```
32
+
33
+ `compile()` returns a function. Call it with your input dict. Pass `data=` for values the template reads with `@`:
34
+
35
+ ```python
36
+ render = hb.compile('{{name}} / {{@request_id}}')
37
+ print(render({'name': 'Ana'}, data={'request_id': 'r-42'}))
38
+ # => Ana / r-42
39
+ ```
40
+
41
+ ## Helpers
42
+
43
+ A helper is `fn(args, options)`. `args` holds the positional arguments and `options.hash` holds the `key=value` ones.
44
+
45
+ ```python
46
+ def price(args, options):
47
+ cents = args[0]
48
+ currency = options.hash.get('currency', 'USD')
49
+ return f'{cents / 100:.2f} {currency}'
50
+
51
+
52
+ hb.register_helper('price', price)
53
+ print(hb.compile('Salmon: {{price cents currency="EUR"}}')({'cents': 1850}))
54
+ # => Salmon: 18.50 EUR
55
+ ```
56
+
57
+ For a block helper (`{{#name}}...{{/name}}`), `options.fn(context)` renders the body and `options.inverse(context)` renders the `{{else}}` body:
58
+
59
+ ```python
60
+ def loud(args, options):
61
+ return options.fn(options.context).upper()
62
+
63
+
64
+ hb.register_helper('loud', loud)
65
+ print(hb.compile('{{#loud}}chef says {{dish}}{{/loud}}')({'dish': 'tartine'}))
66
+ # => CHEF SAYS TARTINE
67
+ ```
68
+
69
+ `options.context` holds the current scope. For backward compatibility with `handlebarrz`, calling `options.context()` returns the dictionary.
70
+
71
+ Helper output gets escaped like any other value. Return a `SafeString` to insert markup as written. Escaping is then up to you.
72
+
73
+ `if`, `unless`, `each`, `with`, `lookup`, and `log` are built in. You can't override them with `register_helper`.
74
+
75
+ ## Partials
76
+
77
+ ```python
78
+ hb.register_partial('dish', '- {{name}} ({{price}})\n')
79
+ render = hb.compile('Menu:\n{{#each dishes}}{{> dish}}{{/each}}')
80
+ print(render({'dishes': [{'name': 'Tartine', 'price': 14}, {'name': 'Soup', 'price': 9}]}))
81
+ # => Menu:
82
+ # - Tartine (14)
83
+ # - Soup (9)
84
+ ```
85
+
86
+ A missing partial raises. `{{#> name}}fallback{{/name}}` renders the fallback instead. Inline partials (`{{#*inline "name"}}`) and dynamic partials (`{{> (helperName)}}`) work too.
87
+
88
+ ## Escaping
89
+
90
+ `{{value}}` HTML-escapes by default. `{{{value}}}` doesn't.
91
+
92
+ ```python
93
+ render = Handlebars().compile('{{note}} | {{{note}}}')
94
+ print(render({'note': 'Fish & <b>Chips</b>'}))
95
+ # => Fish &amp; &lt;b&gt;Chips&lt;/b&gt; | Fish & <b>Chips</b>
96
+ ```
97
+
98
+ Prompts usually go to a model, not a browser. To turn escaping off everywhere, use `Handlebars(escape_html=False)`.
99
+
100
+ ## Strict mode
101
+
102
+ `Handlebars(strict=True)` raises when the template prints a path that isn't in the input:
103
+
104
+ ```python
105
+ from dotpromptz_handlebars import Handlebars, StrictModeError
106
+
107
+ try:
108
+ Handlebars(strict=True).compile('Hello {{user.name}}')({'user': {}})
109
+ except StrictModeError as err:
110
+ print(err.path)
111
+ # => user.name
112
+ ```
113
+
114
+ Conditions don't raise. `{{#if user.name}}` on a missing path takes the else branch.
115
+
116
+ ## Values that surprise Python developers
117
+
118
+ Dotprompt defines what a template means, independent of the language that renders it. Dotprompt templates use Handlebars semantics, and this package takes them from Handlebars.js 4.7.9. Conditionals and printed values follow those semantics, not Python's `bool()` or `str()`:
119
+
120
+ - `0` fails `{{#if}}` but enters `{{#with}}`. Use `{{#if n includeZero=true}}` to keep `0`.
121
+ - `{}` enters `{{#if}}`. `{{#if}}` takes the else branch only for a missing key, `None`, `False`, `""`, `0`, or `[]`.
122
+ - Lists print as `1,2` and dicts print as `[object Object]`. Format structured data with a helper. Dotprompt ships `{{json value}}` for this.
123
+ - `1.0` prints as `1`, and `False` prints as `false`.
124
+
125
+ ## What's not supported
126
+
127
+ These raise `ValueError`:
128
+
129
+ - Decorators (`{{* name}}`).
130
+ - Functions in the input dict. Register them with `register_helper`, so a template can only call code you chose.
131
+ - Broken templates. Which templates fail matches Handlebars.js, but the error messages are worded differently.
132
+
133
+ Everything else a prompt uses is supported:
134
+ - **Paths:** `user.name`, `../name`, `items.[0]`
135
+ - **Blocks:** `if`, `unless`, `each`, `with`, with `else` and `else if`
136
+ - **Block parameters:** `as |item index|`
137
+ - **Data:** `@index`, `@key`, `@first`, `@last`, `@root`
138
+ - **Syntax:** subexpressions, comments, `~` whitespace control, and raw blocks (`{{{{raw}}}}`)
@@ -0,0 +1,67 @@
1
+ # Copyright 2026 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ # SPDX-License-Identifier: Apache-2.0
16
+
17
+ """A pure Python Handlebars template engine."""
18
+
19
+ from dotpromptz_handlebars._compiler import (
20
+ EscapeFunction,
21
+ Handlebars,
22
+ HelperFn,
23
+ RuntimeOptions,
24
+ )
25
+ from dotpromptz_handlebars._render import StrictModeError
26
+ from dotpromptz_handlebars._types import (
27
+ Block,
28
+ BlockFn,
29
+ Context,
30
+ ContextDict,
31
+ ElseNode,
32
+ HelperOptions,
33
+ InlinePartial,
34
+ Mustache,
35
+ Node,
36
+ Partial,
37
+ PartialBlock,
38
+ Program,
39
+ SafeString,
40
+ TagToken,
41
+ TemplateRecursionError,
42
+ Text,
43
+ )
44
+
45
+ __all__ = [
46
+ 'Block',
47
+ 'BlockFn',
48
+ 'Context',
49
+ 'ContextDict',
50
+ 'ElseNode',
51
+ 'EscapeFunction',
52
+ 'Handlebars',
53
+ 'HelperFn',
54
+ 'HelperOptions',
55
+ 'InlinePartial',
56
+ 'Mustache',
57
+ 'Node',
58
+ 'Partial',
59
+ 'PartialBlock',
60
+ 'Program',
61
+ 'RuntimeOptions',
62
+ 'SafeString',
63
+ 'StrictModeError',
64
+ 'TagToken',
65
+ 'TemplateRecursionError',
66
+ 'Text',
67
+ ]