chevron-ng 0.15.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.
- chevron_ng-0.15.0/LICENSE +21 -0
- chevron_ng-0.15.0/PKG-INFO +219 -0
- chevron_ng-0.15.0/README.md +197 -0
- chevron_ng-0.15.0/pyproject.toml +83 -0
- chevron_ng-0.15.0/pyproject.toml.orig +75 -0
- chevron_ng-0.15.0/src/chevron/__init__.py +21 -0
- chevron_ng-0.15.0/src/chevron/main.py +126 -0
- chevron_ng-0.15.0/src/chevron/renderer.py +852 -0
- chevron_ng-0.15.0/src/chevron/tokenizer.py +304 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Noah Morrison
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chevron-ng
|
|
3
|
+
Version: 0.15.0
|
|
4
|
+
Summary: Mustache templating language renderer
|
|
5
|
+
Author: Noah Morrison
|
|
6
|
+
Author-email: Noah Morrison <noah@morrison.ph>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
17
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Project-URL: Homepage, https://github.com/deeprave/chevron
|
|
20
|
+
Project-URL: Repository, https://github.com/deeprave/chevron
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
[](https://badge.fury.io/py/chevron-ng)
|
|
24
|
+
|
|
25
|
+
A Python implementation of the [Mustache templating language](https://mustache.github.io).
|
|
26
|
+
|
|
27
|
+
This is a direct fork of the now-unmaintained [noahmorrison/chevron](https://github.com/noahmorrison/chevron). It builds on that implementation, modernising the project, closing potential security gaps around template extensions, and bringing Mustache compliance up to date.
|
|
28
|
+
|
|
29
|
+
Future work includes asynchronous rendering and asynchronous partial handling.
|
|
30
|
+
|
|
31
|
+
Why chevron?
|
|
32
|
+
------------
|
|
33
|
+
|
|
34
|
+
I'm glad you asked!
|
|
35
|
+
|
|
36
|
+
### chevron is fast ###
|
|
37
|
+
|
|
38
|
+
Chevron runs in less than half the time of [pystache](http://github.com/defunkt/pystache) (Which is not even up to date on the spec).
|
|
39
|
+
And in about 70% the time of [Stache](https://github.com/hyperturtle/Stache) (A 'trimmed' version of mustache, also not spec compliant).
|
|
40
|
+
|
|
41
|
+
### chevron is spec compliant ###
|
|
42
|
+
|
|
43
|
+
Chevron includes a pinned copy of the [Mustache specification](https://github.com/mustache/spec) fixtures, including lambda cases. See the fixture [attribution README](tests/fixtures/mustache-spec/README.md).
|
|
44
|
+
|
|
45
|
+
If you find a test that Chevron does not pass, please [report it](https://github.com/deeprave/chevron/issues/new).
|
|
46
|
+
|
|
47
|
+
### chevron supports modern Python ###
|
|
48
|
+
|
|
49
|
+
Chevron requires Python 3.11 or later.
|
|
50
|
+
|
|
51
|
+
Development and verification
|
|
52
|
+
----------------------------
|
|
53
|
+
|
|
54
|
+
Install the development environment with `uv sync --dev`, then run `uv run pytest`. Chevron's own behavioural tests are separate from the vendored Mustache specification fixtures, which are retained unchanged as the deterministic conformance suite. Bounded Hypothesis properties complement those examples by exercising renderer and tokenizer invariants over generated input.
|
|
55
|
+
|
|
56
|
+
USAGE
|
|
57
|
+
-----
|
|
58
|
+
|
|
59
|
+
Commandline usage: (if installed via pypi)
|
|
60
|
+
```
|
|
61
|
+
usage: chevron [-h] [-v] [-d DATA] [-p PARTIALS_PATH] [-e PARTIALS_EXT]
|
|
62
|
+
[-l DEF_LDEL] [-r DEF_RDEL]
|
|
63
|
+
template
|
|
64
|
+
|
|
65
|
+
positional arguments:
|
|
66
|
+
template The mustache file
|
|
67
|
+
|
|
68
|
+
optional arguments:
|
|
69
|
+
-h, --help show this help message and exit
|
|
70
|
+
-v, --version show program's version number and exit
|
|
71
|
+
-d DATA, --data DATA The json data file
|
|
72
|
+
-p PARTIALS_PATH, --path PARTIALS_PATH
|
|
73
|
+
The directory where your partials reside
|
|
74
|
+
-e PARTIALS_EXT, --ext PARTIALS_EXT
|
|
75
|
+
The extension for your mustache partials, 'mustache'
|
|
76
|
+
by default
|
|
77
|
+
-l DEF_LDEL, --left-delimiter DEF_LDEL
|
|
78
|
+
The default left delimiter, "{{" by default.
|
|
79
|
+
-r DEF_RDEL, --right-delimiter DEF_RDEL
|
|
80
|
+
The default right delimiter, "}}" by default.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Python usage with strings
|
|
84
|
+
```python
|
|
85
|
+
import chevron
|
|
86
|
+
|
|
87
|
+
chevron.render("Hello, {{ mustache }}!", {"mustache": "World"})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Python usage with file
|
|
91
|
+
```python
|
|
92
|
+
import chevron
|
|
93
|
+
|
|
94
|
+
with open("file.mustache", "r") as f:
|
|
95
|
+
chevron.render(f, {"mustache": "World"})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Python usage with unpacking
|
|
99
|
+
```python
|
|
100
|
+
import chevron
|
|
101
|
+
|
|
102
|
+
args = {"template": "Hello, {{ mustache }}!", "data": {"mustache": "World"}}
|
|
103
|
+
|
|
104
|
+
chevron.render(**args)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
chevron supports partials (via dictionaries)
|
|
108
|
+
```python
|
|
109
|
+
import chevron
|
|
110
|
+
|
|
111
|
+
args = {"template": "Hello, {{> thing }}!", "partials_dict": {"thing": "World"}}
|
|
112
|
+
|
|
113
|
+
chevron.render(**args)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
chevron supports partials (via the filesystem)
|
|
117
|
+
```python
|
|
118
|
+
import chevron
|
|
119
|
+
|
|
120
|
+
args = {
|
|
121
|
+
"template": "Hello, {{> thing }}!",
|
|
122
|
+
# filesystem lookup is enabled only when this path is supplied
|
|
123
|
+
"partials_path": "partials/",
|
|
124
|
+
# defaults to mustache
|
|
125
|
+
"partials_ext": "ms",
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# ./partials/thing.ms will be read and rendered
|
|
129
|
+
chevron.render(**args)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
chevron supports lambdas
|
|
133
|
+
|
|
134
|
+
For new code, use the `lambdas=` mapping to declare the callable protocol for each render. Registered names are resolved before template data, and template-data callables are rejected in explicit mode. This keeps executable extensions separate from the data exposed to a template. This is the recommended mode for untrusted templates, although it is not a general template sandbox.
|
|
135
|
+
|
|
136
|
+
Use `@chevron.func` for a zero-argument interpolation lambda. Chevron renders its returned text with the render's configured default delimiters, then applies the escaping requested by the interpolation tag. The decorator is required for this new protocol whether the callable is supplied through `lambdas=` or ordinary compatibility-mode template data.
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
import chevron
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@chevron.func
|
|
143
|
+
def greeting():
|
|
144
|
+
return "{{name}}"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
chevron.render("Hello, {{greeting}}!", {"name": "Ada"}, lambdas={"greeting": greeting})
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Use `@chevron.section` for a Mustache-standard one-argument section lambda. It receives the unprocessed text between its section tags and Chevron recursively renders its return value using the delimiters active when that section opens. The decorator is required for this new protocol in both explicit and compatibility modes.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
import chevron
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@chevron.section
|
|
157
|
+
def repeat(text):
|
|
158
|
+
return text + text
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
chevron.render(
|
|
162
|
+
"{{#repeat}}{{name}}{{/repeat}}", {"name": "Ada"}, lambdas={"repeat": repeat}
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Use `@chevron.compat` for Chevron’s original two-argument section callback. It receives the historical compatibility text and a `render()` callback which can render it with optional temporary data. That helper starts with the render's configured default delimiters. Undecorated section callbacks continue to use this protocol, but the decorator makes compatibility usage explicit and easy to find.
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
import chevron
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@chevron.compat
|
|
173
|
+
def select_first(text, render):
|
|
174
|
+
return render(text).split(" || ", 1)[0]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
chevron.render(
|
|
178
|
+
"{{#select_first}}{{first}} || {{second}}{{/select_first}}",
|
|
179
|
+
{"first": "one", "second": "two"},
|
|
180
|
+
lambdas={"select_first": select_first},
|
|
181
|
+
)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Pass `lambdas={}` to configure no callable section tags explicitly. In explicit mode, callable values in template data are rejected and render as empty values; with `warn=True`, Chevron writes a diagnostic (currently to standard error). A lambda which returns `None` also renders as an empty value and emits that diagnostic when warnings are enabled. Callable values are also lookup leaves, so a template cannot traverse their attributes.
|
|
185
|
+
|
|
186
|
+
This is intentional for all callable values, including callable instances and classes. For example, `{{build.version}}` does not traverse a callable `build` in explicit mode. Expose only the needed plain data through an authorised section lambda instead:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
def build(text, render):
|
|
190
|
+
return render(text, {"version": Build.version})
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
chevron.render(
|
|
194
|
+
"{{#build}}{{version}}{{/build}}",
|
|
195
|
+
{},
|
|
196
|
+
lambdas={"build": build},
|
|
197
|
+
)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Omitting `lambdas` (or passing `None`) retains Chevron's permissive compatibility mode so existing two-argument section callbacks keep working. In this mode, callable values resolved through normal mapping or sequence lookup may execute, including after a non-callable object attribute. A callable obtained directly from an object attribute is still not invoked. Undecorated interpolation callables keep their historic stringification behaviour; use `@chevron.func` to invoke one.
|
|
201
|
+
|
|
202
|
+
For untrusted templates, always provide an explicit `lambdas` mapping, even if it is empty. This controls callable section execution only; it is not a general template sandbox. Keep secrets and rich objects out of template data, supply only plain values where possible.
|
|
203
|
+
|
|
204
|
+
Library renders now disable filesystem partial lookup by default. Use vetted partial source in `partials_dict`, or opt in to a trusted filesystem directory:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
chevron.render(template, data, partials_path="/srv/app/partials")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Use `partials_path="."` only when restoring the historic process-current-
|
|
211
|
+
directory lookup intentionally, but this can potentially leak server data if poorly crafted or untrusted templates are rendered.
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
TODO
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
* get popular
|
|
218
|
+
* have people complain
|
|
219
|
+
* fix those complaints
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
[](https://badge.fury.io/py/chevron-ng)
|
|
2
|
+
|
|
3
|
+
A Python implementation of the [Mustache templating language](https://mustache.github.io).
|
|
4
|
+
|
|
5
|
+
This is a direct fork of the now-unmaintained [noahmorrison/chevron](https://github.com/noahmorrison/chevron). It builds on that implementation, modernising the project, closing potential security gaps around template extensions, and bringing Mustache compliance up to date.
|
|
6
|
+
|
|
7
|
+
Future work includes asynchronous rendering and asynchronous partial handling.
|
|
8
|
+
|
|
9
|
+
Why chevron?
|
|
10
|
+
------------
|
|
11
|
+
|
|
12
|
+
I'm glad you asked!
|
|
13
|
+
|
|
14
|
+
### chevron is fast ###
|
|
15
|
+
|
|
16
|
+
Chevron runs in less than half the time of [pystache](http://github.com/defunkt/pystache) (Which is not even up to date on the spec).
|
|
17
|
+
And in about 70% the time of [Stache](https://github.com/hyperturtle/Stache) (A 'trimmed' version of mustache, also not spec compliant).
|
|
18
|
+
|
|
19
|
+
### chevron is spec compliant ###
|
|
20
|
+
|
|
21
|
+
Chevron includes a pinned copy of the [Mustache specification](https://github.com/mustache/spec) fixtures, including lambda cases. See the fixture [attribution README](tests/fixtures/mustache-spec/README.md).
|
|
22
|
+
|
|
23
|
+
If you find a test that Chevron does not pass, please [report it](https://github.com/deeprave/chevron/issues/new).
|
|
24
|
+
|
|
25
|
+
### chevron supports modern Python ###
|
|
26
|
+
|
|
27
|
+
Chevron requires Python 3.11 or later.
|
|
28
|
+
|
|
29
|
+
Development and verification
|
|
30
|
+
----------------------------
|
|
31
|
+
|
|
32
|
+
Install the development environment with `uv sync --dev`, then run `uv run pytest`. Chevron's own behavioural tests are separate from the vendored Mustache specification fixtures, which are retained unchanged as the deterministic conformance suite. Bounded Hypothesis properties complement those examples by exercising renderer and tokenizer invariants over generated input.
|
|
33
|
+
|
|
34
|
+
USAGE
|
|
35
|
+
-----
|
|
36
|
+
|
|
37
|
+
Commandline usage: (if installed via pypi)
|
|
38
|
+
```
|
|
39
|
+
usage: chevron [-h] [-v] [-d DATA] [-p PARTIALS_PATH] [-e PARTIALS_EXT]
|
|
40
|
+
[-l DEF_LDEL] [-r DEF_RDEL]
|
|
41
|
+
template
|
|
42
|
+
|
|
43
|
+
positional arguments:
|
|
44
|
+
template The mustache file
|
|
45
|
+
|
|
46
|
+
optional arguments:
|
|
47
|
+
-h, --help show this help message and exit
|
|
48
|
+
-v, --version show program's version number and exit
|
|
49
|
+
-d DATA, --data DATA The json data file
|
|
50
|
+
-p PARTIALS_PATH, --path PARTIALS_PATH
|
|
51
|
+
The directory where your partials reside
|
|
52
|
+
-e PARTIALS_EXT, --ext PARTIALS_EXT
|
|
53
|
+
The extension for your mustache partials, 'mustache'
|
|
54
|
+
by default
|
|
55
|
+
-l DEF_LDEL, --left-delimiter DEF_LDEL
|
|
56
|
+
The default left delimiter, "{{" by default.
|
|
57
|
+
-r DEF_RDEL, --right-delimiter DEF_RDEL
|
|
58
|
+
The default right delimiter, "}}" by default.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Python usage with strings
|
|
62
|
+
```python
|
|
63
|
+
import chevron
|
|
64
|
+
|
|
65
|
+
chevron.render("Hello, {{ mustache }}!", {"mustache": "World"})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Python usage with file
|
|
69
|
+
```python
|
|
70
|
+
import chevron
|
|
71
|
+
|
|
72
|
+
with open("file.mustache", "r") as f:
|
|
73
|
+
chevron.render(f, {"mustache": "World"})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Python usage with unpacking
|
|
77
|
+
```python
|
|
78
|
+
import chevron
|
|
79
|
+
|
|
80
|
+
args = {"template": "Hello, {{ mustache }}!", "data": {"mustache": "World"}}
|
|
81
|
+
|
|
82
|
+
chevron.render(**args)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
chevron supports partials (via dictionaries)
|
|
86
|
+
```python
|
|
87
|
+
import chevron
|
|
88
|
+
|
|
89
|
+
args = {"template": "Hello, {{> thing }}!", "partials_dict": {"thing": "World"}}
|
|
90
|
+
|
|
91
|
+
chevron.render(**args)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
chevron supports partials (via the filesystem)
|
|
95
|
+
```python
|
|
96
|
+
import chevron
|
|
97
|
+
|
|
98
|
+
args = {
|
|
99
|
+
"template": "Hello, {{> thing }}!",
|
|
100
|
+
# filesystem lookup is enabled only when this path is supplied
|
|
101
|
+
"partials_path": "partials/",
|
|
102
|
+
# defaults to mustache
|
|
103
|
+
"partials_ext": "ms",
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# ./partials/thing.ms will be read and rendered
|
|
107
|
+
chevron.render(**args)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
chevron supports lambdas
|
|
111
|
+
|
|
112
|
+
For new code, use the `lambdas=` mapping to declare the callable protocol for each render. Registered names are resolved before template data, and template-data callables are rejected in explicit mode. This keeps executable extensions separate from the data exposed to a template. This is the recommended mode for untrusted templates, although it is not a general template sandbox.
|
|
113
|
+
|
|
114
|
+
Use `@chevron.func` for a zero-argument interpolation lambda. Chevron renders its returned text with the render's configured default delimiters, then applies the escaping requested by the interpolation tag. The decorator is required for this new protocol whether the callable is supplied through `lambdas=` or ordinary compatibility-mode template data.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
import chevron
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@chevron.func
|
|
121
|
+
def greeting():
|
|
122
|
+
return "{{name}}"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
chevron.render("Hello, {{greeting}}!", {"name": "Ada"}, lambdas={"greeting": greeting})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Use `@chevron.section` for a Mustache-standard one-argument section lambda. It receives the unprocessed text between its section tags and Chevron recursively renders its return value using the delimiters active when that section opens. The decorator is required for this new protocol in both explicit and compatibility modes.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import chevron
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@chevron.section
|
|
135
|
+
def repeat(text):
|
|
136
|
+
return text + text
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
chevron.render(
|
|
140
|
+
"{{#repeat}}{{name}}{{/repeat}}", {"name": "Ada"}, lambdas={"repeat": repeat}
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Use `@chevron.compat` for Chevron’s original two-argument section callback. It receives the historical compatibility text and a `render()` callback which can render it with optional temporary data. That helper starts with the render's configured default delimiters. Undecorated section callbacks continue to use this protocol, but the decorator makes compatibility usage explicit and easy to find.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
import chevron
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@chevron.compat
|
|
151
|
+
def select_first(text, render):
|
|
152
|
+
return render(text).split(" || ", 1)[0]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
chevron.render(
|
|
156
|
+
"{{#select_first}}{{first}} || {{second}}{{/select_first}}",
|
|
157
|
+
{"first": "one", "second": "two"},
|
|
158
|
+
lambdas={"select_first": select_first},
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Pass `lambdas={}` to configure no callable section tags explicitly. In explicit mode, callable values in template data are rejected and render as empty values; with `warn=True`, Chevron writes a diagnostic (currently to standard error). A lambda which returns `None` also renders as an empty value and emits that diagnostic when warnings are enabled. Callable values are also lookup leaves, so a template cannot traverse their attributes.
|
|
163
|
+
|
|
164
|
+
This is intentional for all callable values, including callable instances and classes. For example, `{{build.version}}` does not traverse a callable `build` in explicit mode. Expose only the needed plain data through an authorised section lambda instead:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
def build(text, render):
|
|
168
|
+
return render(text, {"version": Build.version})
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
chevron.render(
|
|
172
|
+
"{{#build}}{{version}}{{/build}}",
|
|
173
|
+
{},
|
|
174
|
+
lambdas={"build": build},
|
|
175
|
+
)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Omitting `lambdas` (or passing `None`) retains Chevron's permissive compatibility mode so existing two-argument section callbacks keep working. In this mode, callable values resolved through normal mapping or sequence lookup may execute, including after a non-callable object attribute. A callable obtained directly from an object attribute is still not invoked. Undecorated interpolation callables keep their historic stringification behaviour; use `@chevron.func` to invoke one.
|
|
179
|
+
|
|
180
|
+
For untrusted templates, always provide an explicit `lambdas` mapping, even if it is empty. This controls callable section execution only; it is not a general template sandbox. Keep secrets and rich objects out of template data, supply only plain values where possible.
|
|
181
|
+
|
|
182
|
+
Library renders now disable filesystem partial lookup by default. Use vetted partial source in `partials_dict`, or opt in to a trusted filesystem directory:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
chevron.render(template, data, partials_path="/srv/app/partials")
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Use `partials_path="."` only when restoring the historic process-current-
|
|
189
|
+
directory lookup intentionally, but this can potentially leak server data if poorly crafted or untrusted templates are rendered.
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
TODO
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
* get popular
|
|
196
|
+
* have people complain
|
|
197
|
+
* fix those complaints
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.12.15,<0.14"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[tool.uv]
|
|
6
|
+
required-version = "==0.13.1"
|
|
7
|
+
|
|
8
|
+
[tool.uv.build-backend]
|
|
9
|
+
module-name = "chevron"
|
|
10
|
+
|
|
11
|
+
[tool.pytest.ini_options]
|
|
12
|
+
testpaths = ["tests"]
|
|
13
|
+
pythonpath = ["src"]
|
|
14
|
+
addopts = [
|
|
15
|
+
"--strict-markers",
|
|
16
|
+
"--strict-config",
|
|
17
|
+
"--cov=chevron",
|
|
18
|
+
"--cov-report=term-missing",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.coverage.run]
|
|
22
|
+
branch = true
|
|
23
|
+
source = ["chevron"]
|
|
24
|
+
|
|
25
|
+
[tool.coverage.report]
|
|
26
|
+
exclude_lines = [
|
|
27
|
+
"if __name__ == .__main__.:",
|
|
28
|
+
"def cli_main",
|
|
29
|
+
"# python 2",
|
|
30
|
+
"# not tested",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[tool.ruff]
|
|
34
|
+
src = ["src"]
|
|
35
|
+
target-version = "py311"
|
|
36
|
+
|
|
37
|
+
[tool.ruff.lint]
|
|
38
|
+
select = [
|
|
39
|
+
"E4",
|
|
40
|
+
"E7",
|
|
41
|
+
"E9",
|
|
42
|
+
"F",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project]
|
|
46
|
+
name = "chevron-ng"
|
|
47
|
+
version = "0.15.0"
|
|
48
|
+
description = "Mustache templating language renderer"
|
|
49
|
+
readme = "README.md"
|
|
50
|
+
requires-python = ">=3.11"
|
|
51
|
+
license = "MIT"
|
|
52
|
+
license-files = ["LICENSE"]
|
|
53
|
+
classifiers = [
|
|
54
|
+
"Development Status :: 4 - Beta",
|
|
55
|
+
"Programming Language :: Python :: 3",
|
|
56
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
57
|
+
"Programming Language :: Python :: 3.11",
|
|
58
|
+
"Programming Language :: Python :: 3.12",
|
|
59
|
+
"Programming Language :: Python :: 3.13",
|
|
60
|
+
"Programming Language :: Python :: 3.14",
|
|
61
|
+
"Programming Language :: Python :: 3.15",
|
|
62
|
+
"Topic :: Text Processing :: Markup",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[project.authors]]
|
|
66
|
+
name = "Noah Morrison"
|
|
67
|
+
email = "noah@morrison.ph"
|
|
68
|
+
|
|
69
|
+
[project.urls]
|
|
70
|
+
Homepage = "https://github.com/deeprave/chevron"
|
|
71
|
+
Repository = "https://github.com/deeprave/chevron"
|
|
72
|
+
|
|
73
|
+
[project.scripts]
|
|
74
|
+
chevron = "chevron:cli_main"
|
|
75
|
+
|
|
76
|
+
[dependency-groups]
|
|
77
|
+
dev = [
|
|
78
|
+
"hypothesis>=6.170.1",
|
|
79
|
+
"pytest",
|
|
80
|
+
"pytest-cov>=7.1.0",
|
|
81
|
+
"ruff",
|
|
82
|
+
"ty",
|
|
83
|
+
]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.12.15,<0.14"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[tool.uv.build-backend]
|
|
6
|
+
module-name = "chevron"
|
|
7
|
+
|
|
8
|
+
[tool.uv]
|
|
9
|
+
required-version = "==0.13.1"
|
|
10
|
+
|
|
11
|
+
[project]
|
|
12
|
+
name = "chevron-ng"
|
|
13
|
+
version = "0.15.0"
|
|
14
|
+
description = "Mustache templating language renderer"
|
|
15
|
+
readme = "README.md"
|
|
16
|
+
requires-python = ">=3.11"
|
|
17
|
+
license = "MIT"
|
|
18
|
+
license-files = ["LICENSE"]
|
|
19
|
+
authors = [{ name = "Noah Morrison", email = "noah@morrison.ph" }]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Programming Language :: Python :: 3.15",
|
|
29
|
+
"Topic :: Text Processing :: Markup",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/deeprave/chevron"
|
|
34
|
+
Repository = "https://github.com/deeprave/chevron"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
chevron = "chevron:cli_main"
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = [
|
|
41
|
+
"hypothesis>=6.170.1",
|
|
42
|
+
"pytest",
|
|
43
|
+
"pytest-cov>=7.1.0",
|
|
44
|
+
"ruff",
|
|
45
|
+
"ty",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
pythonpath = ["src"]
|
|
51
|
+
addopts = [
|
|
52
|
+
"--strict-markers",
|
|
53
|
+
"--strict-config",
|
|
54
|
+
"--cov=chevron",
|
|
55
|
+
"--cov-report=term-missing",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.coverage.run]
|
|
59
|
+
branch = true
|
|
60
|
+
source = ["chevron"]
|
|
61
|
+
|
|
62
|
+
[tool.coverage.report]
|
|
63
|
+
exclude_lines = [
|
|
64
|
+
"if __name__ == .__main__.:",
|
|
65
|
+
"def cli_main",
|
|
66
|
+
"# python 2",
|
|
67
|
+
"# not tested",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[tool.ruff]
|
|
71
|
+
src = ["src"]
|
|
72
|
+
target-version = "py311"
|
|
73
|
+
|
|
74
|
+
[tool.ruff.lint]
|
|
75
|
+
select = ["E4", "E7", "E9", "F"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
__version__ = version("chevron-ng")
|
|
5
|
+
except PackageNotFoundError:
|
|
6
|
+
__version__ = "0+unknown"
|
|
7
|
+
|
|
8
|
+
from .main import main, cli_main
|
|
9
|
+
from .renderer import compat, func, render, section
|
|
10
|
+
from .tokenizer import ChevronError
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"main",
|
|
14
|
+
"render",
|
|
15
|
+
"cli_main",
|
|
16
|
+
"ChevronError",
|
|
17
|
+
"compat",
|
|
18
|
+
"func",
|
|
19
|
+
"section",
|
|
20
|
+
"__version__",
|
|
21
|
+
]
|