fstache 0.1.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.
fstache-0.1.0/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ Zero-Clause BSD
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted.
5
+
6
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
7
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
8
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
10
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
11
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
12
+ PERFORMANCE OF THIS SOFTWARE.
fstache-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: fstache
3
+ Version: 0.1.0
4
+ Summary: A fast and realistic Mustache-based HTML generator
5
+ Author: vkorobkov
6
+ License-Expression: 0BSD
7
+ License-File: LICENSE
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Requires-Dist: ruff>=0.6.0 ; extra == 'dev'
13
+ Requires-Dist: chevron==0.14.0 ; extra == 'dev'
14
+ Requires-Dist: mstache==0.3.0 ; extra == 'dev'
15
+ Requires-Dist: pystache==0.6.8 ; extra == 'dev'
16
+ Requires-Dist: pytest ; extra == 'dev'
17
+ Requires-Dist: ty ; extra == 'dev'
18
+ Requires-Python: >=3.12
19
+ Project-URL: Homepage, https://github.com/servletcloud/fstache
20
+ Project-URL: Repository, https://github.com/servletcloud/fstache
21
+ Project-URL: Issues, https://github.com/servletcloud/fstache/issues
22
+ Provides-Extra: dev
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Fstache
26
+
27
+ ## Overview
28
+
29
+ - Dependency-free [Mustache](https://mustache.github.io/) renderer for
30
+ [Python 3.12+](https://docs.python.org/3.12/).
31
+ - Supports [upstream Mustache spec fixtures](https://github.com/mustache/spec),
32
+ including lambdas and dynamic partial names; **inheritance is unsupported**.
33
+ - Built for speed; [benchmarked](#benchmarks) at 3.3x
34
+ [Chevron](https://github.com/noahmorrison/chevron), 3.1x
35
+ [mstache](https://pypi.org/project/mstache/), and 3.5x
36
+ [Pystache](https://github.com/defunkt/pystache).
37
+ - [PEP 561](https://peps.python.org/pep-0561/) typed package.
38
+ - Supports Python mappings, objects, sequences, and callables as render data.
39
+ - Static partials are preloaded and inlined, eliminating render-time boundary overhead.
40
+
41
+
42
+ ## Benchmarks
43
+
44
+ ### Renderer Throughput
45
+
46
+ | Library | Renders per second | Indentation details |
47
+ | --- | ---: | --- |
48
+ | Fstache | 4066.5 | **Deviates**: `ignore_indents=True` skips standard standalone partial reindentation. |
49
+ | Fstache | 3102.2 | Follows standard standalone partial indentation. |
50
+ | mstache | 1339.0 | **Deviates**: `keep_lines=True` keeps tag-only lines instead of collapsing them, so partial indentation is not reapplied to every partial line. |
51
+ | mstache | 985.3 | Follows standard standalone partial indentation. |
52
+ | Chevron | 951.1 | Follows standard standalone partial indentation. |
53
+ | Pystache | 898.8 | Follows standard standalone partial indentation. |
54
+
55
+
56
+ ### Benchmark environment
57
+
58
+ | Field | Value |
59
+ | --- | --- |
60
+ | Python | CPython 3.14.6 |
61
+ | OS | Fedora Linux 44 (Workstation Edition), Linux 7.0.12-201.fc44.x86_64 |
62
+ | CPU | AMD Ryzen 7 8845HS w/ Radeon 780M Graphics, 8 cores / 16 threads |
63
+ | Compared versions | Fstache 0.1.0, Chevron 0.14.0, mstache 0.3.0, Pystache 0.6.8 |
64
+ | Command | `RENDERER=<renderer> uv run --python 3.14 --extra dev python tests/perf_test.py`<br>`<renderer>` values: `fstache.no_indentation`, `fstache`, `mstache.no_indentation`, `mstache`, `chevron`, `pystache` |
65
+
66
+
67
+ ### Methodology
68
+
69
+ - The benchmark renders a realistic, heavy marketing/docs HTML page from the
70
+ [source Mustache templates](demo/templates), [JSON data](demo/data.json), and
71
+ [perf script](tests/perf_test.py):
72
+ - About 100 KiB of [rendered HTML](https://servletcloud.github.io/fstache/)
73
+ ([source](demo/dist/index.html)) from 15 Mustache templates, including 14
74
+ partial files.
75
+ - Tailwind CSS v4 utility-heavy markup with Alpine.js attributes, inline SVG
76
+ icons, responsive navigation, cards, tables, accordions, and form controls.
77
+ - About 15 KiB of JSON context data with nested arrays for navigation,
78
+ feature cards, testimonials, a recursive docs tree, comparison rows, blog
79
+ posts, changelog entries, FAQs, and pricing plans.
80
+ - 42 section, inverted-section, and partial references, including 24 section
81
+ tags for loops and conditionals plus recursive `node` partial rendering.
82
+ - The benchmark isolates render throughput from setup work:
83
+ - Each engine preloads the template files and partials during setup.
84
+ - Each engine uses the closest available precompiled, preparsed, or
85
+ pretokenized representation for the layout and partials.
86
+ - The timed render loop excludes disk I/O and one-time template preparation.
87
+
88
+ ---
89
+
90
+ ## Utility Commands
91
+
92
+ ### Generate Reference HTML
93
+ Builds and renders the templates from `./demo` into `./demo/dist/index.html` (performing file I/O):
94
+ ```bash
95
+ make build-html
96
+ ```
97
+
98
+ ### Format and Lint
99
+ Runs ruff checks and auto-formats the project:
100
+ ```bash
101
+ make post-ai-change
102
+ ```
@@ -0,0 +1,78 @@
1
+ # Fstache
2
+
3
+ ## Overview
4
+
5
+ - Dependency-free [Mustache](https://mustache.github.io/) renderer for
6
+ [Python 3.12+](https://docs.python.org/3.12/).
7
+ - Supports [upstream Mustache spec fixtures](https://github.com/mustache/spec),
8
+ including lambdas and dynamic partial names; **inheritance is unsupported**.
9
+ - Built for speed; [benchmarked](#benchmarks) at 3.3x
10
+ [Chevron](https://github.com/noahmorrison/chevron), 3.1x
11
+ [mstache](https://pypi.org/project/mstache/), and 3.5x
12
+ [Pystache](https://github.com/defunkt/pystache).
13
+ - [PEP 561](https://peps.python.org/pep-0561/) typed package.
14
+ - Supports Python mappings, objects, sequences, and callables as render data.
15
+ - Static partials are preloaded and inlined, eliminating render-time boundary overhead.
16
+
17
+
18
+ ## Benchmarks
19
+
20
+ ### Renderer Throughput
21
+
22
+ | Library | Renders per second | Indentation details |
23
+ | --- | ---: | --- |
24
+ | Fstache | 4066.5 | **Deviates**: `ignore_indents=True` skips standard standalone partial reindentation. |
25
+ | Fstache | 3102.2 | Follows standard standalone partial indentation. |
26
+ | mstache | 1339.0 | **Deviates**: `keep_lines=True` keeps tag-only lines instead of collapsing them, so partial indentation is not reapplied to every partial line. |
27
+ | mstache | 985.3 | Follows standard standalone partial indentation. |
28
+ | Chevron | 951.1 | Follows standard standalone partial indentation. |
29
+ | Pystache | 898.8 | Follows standard standalone partial indentation. |
30
+
31
+
32
+ ### Benchmark environment
33
+
34
+ | Field | Value |
35
+ | --- | --- |
36
+ | Python | CPython 3.14.6 |
37
+ | OS | Fedora Linux 44 (Workstation Edition), Linux 7.0.12-201.fc44.x86_64 |
38
+ | CPU | AMD Ryzen 7 8845HS w/ Radeon 780M Graphics, 8 cores / 16 threads |
39
+ | Compared versions | Fstache 0.1.0, Chevron 0.14.0, mstache 0.3.0, Pystache 0.6.8 |
40
+ | Command | `RENDERER=<renderer> uv run --python 3.14 --extra dev python tests/perf_test.py`<br>`<renderer>` values: `fstache.no_indentation`, `fstache`, `mstache.no_indentation`, `mstache`, `chevron`, `pystache` |
41
+
42
+
43
+ ### Methodology
44
+
45
+ - The benchmark renders a realistic, heavy marketing/docs HTML page from the
46
+ [source Mustache templates](demo/templates), [JSON data](demo/data.json), and
47
+ [perf script](tests/perf_test.py):
48
+ - About 100 KiB of [rendered HTML](https://servletcloud.github.io/fstache/)
49
+ ([source](demo/dist/index.html)) from 15 Mustache templates, including 14
50
+ partial files.
51
+ - Tailwind CSS v4 utility-heavy markup with Alpine.js attributes, inline SVG
52
+ icons, responsive navigation, cards, tables, accordions, and form controls.
53
+ - About 15 KiB of JSON context data with nested arrays for navigation,
54
+ feature cards, testimonials, a recursive docs tree, comparison rows, blog
55
+ posts, changelog entries, FAQs, and pricing plans.
56
+ - 42 section, inverted-section, and partial references, including 24 section
57
+ tags for loops and conditionals plus recursive `node` partial rendering.
58
+ - The benchmark isolates render throughput from setup work:
59
+ - Each engine preloads the template files and partials during setup.
60
+ - Each engine uses the closest available precompiled, preparsed, or
61
+ pretokenized representation for the layout and partials.
62
+ - The timed render loop excludes disk I/O and one-time template preparation.
63
+
64
+ ---
65
+
66
+ ## Utility Commands
67
+
68
+ ### Generate Reference HTML
69
+ Builds and renders the templates from `./demo` into `./demo/dist/index.html` (performing file I/O):
70
+ ```bash
71
+ make build-html
72
+ ```
73
+
74
+ ### Format and Lint
75
+ Runs ruff checks and auto-formats the project:
76
+ ```bash
77
+ make post-ai-change
78
+ ```
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.11.25,<0.12"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "fstache"
7
+ version = "0.1.0"
8
+ description = "A fast and realistic Mustache-based HTML generator"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "0BSD"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "vkorobkov" }]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Programming Language :: Python :: 3.14",
19
+ ]
20
+ dependencies = []
21
+
22
+ [project.optional-dependencies]
23
+ dev = [
24
+ "ruff>=0.6.0",
25
+ "chevron==0.14.0",
26
+ "mstache==0.3.0",
27
+ "pystache==0.6.8",
28
+ "pytest",
29
+ "ty"
30
+ ]
31
+
32
+ [tool.uv]
33
+ exclude-newer = "24 hours"
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/servletcloud/fstache"
37
+ Repository = "https://github.com/servletcloud/fstache"
38
+ Issues = "https://github.com/servletcloud/fstache/issues"
@@ -0,0 +1,86 @@
1
+ """Public API for compiling and rendering Fstache templates.
2
+
3
+ The common entry points are :func:`compile`, :func:`render`, and the
4
+ filesystem-backed renderer factories such as :func:`create_renderer`.
5
+ `CompiledTemplate` values are intentionally treated as opaque by the public API:
6
+ loaders, resolvers, and renderers pass them around, but callers should not rely
7
+ on the private node dataclasses unless a future release explicitly promotes
8
+ compiled-template introspection.
9
+ """
10
+
11
+ from ._compiler import (
12
+ DEFAULT_DELIMITERS as DEFAULT_DELIMITERS,
13
+ EMPTY_TEMPLATE as EMPTY_TEMPLATE,
14
+ CompiledTemplate as CompiledTemplate,
15
+ Delimiters as Delimiters,
16
+ InvalidDelimiterError as InvalidDelimiterError,
17
+ InvalidNameError as InvalidNameError,
18
+ SectionSyntaxError as SectionSyntaxError,
19
+ TemplateSyntaxError as TemplateSyntaxError,
20
+ UnclosedTagError as UnclosedTagError,
21
+ UnsupportedTagError as UnsupportedTagError,
22
+ compile as compile,
23
+ )
24
+ from ._factories import (
25
+ TemplateRenderer as TemplateRenderer,
26
+ create_dev_renderer as create_dev_renderer,
27
+ create_prod_renderer as create_prod_renderer,
28
+ create_renderer as create_renderer,
29
+ create_test_renderer as create_test_renderer,
30
+ )
31
+ from ._inliner import inline_partials as inline_partials
32
+ from ._missing import (
33
+ MissingTemplateError as MissingTemplateError,
34
+ MissingTemplateResolver as MissingTemplateResolver,
35
+ MissingVariableError as MissingVariableError,
36
+ MissingVariableResolver as MissingVariableResolver,
37
+ resolve_missing_template_as_empty as resolve_missing_template_as_empty,
38
+ resolve_missing_template_as_error as resolve_missing_template_as_error,
39
+ resolve_missing_variable_as_error as resolve_missing_variable_as_error,
40
+ resolve_missing_variable_as_none as resolve_missing_variable_as_none,
41
+ )
42
+ from ._renderer import (
43
+ EscapeFunction as EscapeFunction,
44
+ TemplateLoader as TemplateLoader,
45
+ RenderChunk as RenderChunk,
46
+ RenderedTemplate as RenderedTemplate,
47
+ TemplateCompiler as TemplateCompiler,
48
+ html_escape as html_escape,
49
+ render as render,
50
+ )
51
+
52
+
53
+ __all__ = (
54
+ "CompiledTemplate",
55
+ "DEFAULT_DELIMITERS",
56
+ "EMPTY_TEMPLATE",
57
+ "Delimiters",
58
+ "EscapeFunction",
59
+ "InvalidDelimiterError",
60
+ "InvalidNameError",
61
+ "MissingTemplateError",
62
+ "MissingTemplateResolver",
63
+ "MissingVariableError",
64
+ "MissingVariableResolver",
65
+ "RenderChunk",
66
+ "RenderedTemplate",
67
+ "SectionSyntaxError",
68
+ "TemplateCompiler",
69
+ "TemplateLoader",
70
+ "TemplateRenderer",
71
+ "TemplateSyntaxError",
72
+ "UnclosedTagError",
73
+ "UnsupportedTagError",
74
+ "compile",
75
+ "create_dev_renderer",
76
+ "create_prod_renderer",
77
+ "create_renderer",
78
+ "create_test_renderer",
79
+ "html_escape",
80
+ "inline_partials",
81
+ "render",
82
+ "resolve_missing_template_as_empty",
83
+ "resolve_missing_template_as_error",
84
+ "resolve_missing_variable_as_error",
85
+ "resolve_missing_variable_as_none",
86
+ )