Simple and efficient Template Engine for Python projects
Project description
Sucuri
Simple and efficient template engine for Python projects, inspired by PugJS.
Sucuri is designed to bring an elegant, indentation-based syntax to Python. By stripping away repetitive HTML tags and taking advantage of natural code structure, Sucuri gives developers a pristine, highly readable HTML rendering experience.
Powered natively by the Lark parser, Sucuri supports deep variable nesting, loops, conditionals, seamless macro injections, and is completely framework-independent. It plays just as well with modern frameworks like FastAPI, Django, and Flask as it does in native Python scripts.
📦 Installation
Install and update using pip:
pip install sucuri
🚀 Quick Start & Integration
Sucuri returns raw HTML strings that can be seamlessly injected into any existing web framework format. All you need is the template function from sucuri.rendering.
Vanilla Python
from sucuri.rendering import template
context = {"name": "World"}
html_output = template("my_template.suc", context)
print(html_output)
⚡ FastAPI Integration
Returns a raw HTMLResponse instantly!
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from sucuri.rendering import template
app = FastAPI()
@app.get("/")
def index():
context = {"name": "FastAPI User"}
html = template('templates/index.suc', context)
return HTMLResponse(content=html, status_code=200)
🌶️ Flask Integration
Use Flask's render_template_string to wrap Sucuri's output.
from flask import Flask, render_template_string
from sucuri.rendering import template
app = Flask(__name__)
@app.route("/")
def index():
context = {"name": "Flask User"}
html = template('templates/index.suc', context)
return render_template_string(html)
🎸 Django Integration
Return the compiled string through HttpResponse.
from django.http import HttpResponse
from sucuri.rendering import template
def index(request):
context = {"name": "Django User"}
html = template('templates/index.suc', context)
return HttpResponse(html)
💻 Command Line Interface (CLI)
Sucuri provides a CLI to directly process .suc templates from your terminal—perfect for shell scripts and static site generation!
# Basic compilation (outputs to stdout)
sucuri build index.suc
# Compilation with output file
sucuri build index.suc -o index.html
# Compilation passing JSON context variables directly inline
sucuri build index.suc --context '{"title": "My Page"}' -o index.html
# Compilation using JSON data loaded from another file
sucuri build index.suc --context context.json -o index.html
📖 Syntax & Features
Basics & Indentation
A standard HTML file doesn't need brackets < >. Instead, Sucuri relies on tabs or spaces (kept strictly uniform) to determine tag hierarchies.
html
body
h1 Title
a(href='#') This is my link
Output:
<html>
<body>
<h1>Title</h1>
<a href="#">This is my link</a>
</body>
</html>
Text
Texts can be described in two ways. Inline together with the tag declaration, or spanning multiple lines starting with the | pipe character.
h3 Hello!
| Text
| with
| more than
| one line
Output:
<h3>Hello!
Text
with
more than
one line
</h3>
Attributes
HTML attributes in Sucuri must be separated by space and enclosed strictly within parentheses (). Unlike standard Pug, they are on a single line and separated by spaces (not commas).
a(href='google.com') Google
a(class='button' href='google.com') Google
div(class='div-class')
input(type="checkbox" checked)
Output:
<a href="google.com">Google</a>
<a class="button" href="google.com">Google</a>
<div class="div-class"></div>
<input type="checkbox" checked>
Dynamic Variables (Context)
Variables passed by Python's context can be effortlessly embedded directly into your text with {}. Sucuri also resolves deeply nested context.
Python Context: {"user": {"name": "Alice", "id": 123}}
Sucuri:
div(class="profile")
h1 Hello {user.name}!
span User ID is {user.id}
Control Flow
You can handle logic natively in .suc files.
If Conditions
Wrap standard comparisons using <if condition> and <endif>.
<if user.status != "banned">
h1 User is active!
<endif>
For Loops
Iterate elegantly using <for item in list>. Access your iterated items dynamically using the hash # symbol (which also supports nested resolution like #item.id!).
Python Context: {"invoices": [{"id": 1}, {"id": 2}]}
ul
<for inv in invoices>
li Invoice Number: #inv.id
<endfor>
📦 Preloaded Templates (Built-in Magic)
Instead of manually crafting standard HTML configurations like ul/li and table setups, Sucuri comes packed with pre-compiled macros for lists and tables to drastically speed up repetitive boilerplate code!
1. Lists & Checkboxes
Pass ANY variable containing an Array, and use the list() built-in to render an entire list matrix automatically.
Python Context: {"my_array": ["Apple", "Orange"], "opts": ["Apple"]}
Unordered List:
list(my_array class="ul-squares")
Result:
<ul class="ul-squares">
<li> Apple </li>
<li> Orange </li>
</ul>
Checkboxes: (Just provide the secondary array containing the checked values!)
list(my_array opts class="survey")
Result:
<input type="checkbox" id="ck-Apple" checked="checked">Apple
<input type="checkbox" id="ck-Orange">Orange
2. Tables
Need a comprehensive HTML table constructed in one go? The table() syntax takes header arrays, rows matrices, and footer arrays automatically!
Python Context:
context = {
"heads": ["Name", "Age"],
"rows": [["Alice", 21], ["Bob", 45]],
"footers": ["End", "End"]
}
Sucuri:
table(heads rows footers class="table" id="tb-authors")
Result:
<table class="table" id="tb-authors">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>21</td>
</tr>
<tr>
<td>Bob</td>
<td>45</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>End</td>
<td>End</td>
</tr>
</tfoot>
</table>
(Positional order: Headers array, Data Matrix array, Footer array.)
🧩 Modularity: Includes, Styles & Scripts
Sucuri acts efficiently as an asset distributor through macro tagging and external inclusions. The engine caches everything natively during execution.
Including Other .suc files
Declare your macro inclusions at the top using include, and instantiate them using the + sign.
modules/button.suc:
button(class='btn-primary') {text}
index.suc:
include modules/button
html
body
h1 Welcome
+button
Injecting CSS Styles and JS Scripts
Need global JS or CSS appended without manually crafting raw headers/footers everywhere? Merely use style and script top-level declarations, supplying their raw path! They will be automatically wrapped in <style> and <script> HTML tags and beautifully appended to the file.
style static/css/global.css
script static/js/app.js
html
body
h1 Wow!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sucuri-1.0.7.tar.gz.
File metadata
- Download URL: sucuri-1.0.7.tar.gz
- Upload date:
- Size: 17.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e255c7347a286926ae7bf12b4ffffefdc85c9ffa559c6fd5c7660b6d31a6208
|
|
| MD5 |
863b3b8d5d8c4e290c35f3a353410146
|
|
| BLAKE2b-256 |
344ce8ec214955d9e1919ab316fece0f8632d3196313539a79ce081a05605416
|
Provenance
The following attestation bundles were made for sucuri-1.0.7.tar.gz:
Publisher:
publish-pypi.yml on marcosstefani/sucuri
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sucuri-1.0.7.tar.gz -
Subject digest:
2e255c7347a286926ae7bf12b4ffffefdc85c9ffa559c6fd5c7660b6d31a6208 - Sigstore transparency entry: 1573498996
- Sigstore integration time:
-
Permalink:
marcosstefani/sucuri@ba687f782a37be0a1d7ff7e2d7a34c80d9bb6192 -
Branch / Tag:
refs/tags/v1.0.7 - Owner: https://github.com/marcosstefani
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@ba687f782a37be0a1d7ff7e2d7a34c80d9bb6192 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sucuri-1.0.7-py2.py3-none-any.whl.
File metadata
- Download URL: sucuri-1.0.7-py2.py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c0f56768c4545ab877de279c32cb036c9e99a7972c37cc913e38e4baa58ea10
|
|
| MD5 |
89201f5f85c88178d83d5ce436fa92fa
|
|
| BLAKE2b-256 |
019fae20a838f2c8baa61862fa9a672fd5feb481b7394ca22a0c1d7830318239
|
Provenance
The following attestation bundles were made for sucuri-1.0.7-py2.py3-none-any.whl:
Publisher:
publish-pypi.yml on marcosstefani/sucuri
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sucuri-1.0.7-py2.py3-none-any.whl -
Subject digest:
0c0f56768c4545ab877de279c32cb036c9e99a7972c37cc913e38e4baa58ea10 - Sigstore transparency entry: 1573499008
- Sigstore integration time:
-
Permalink:
marcosstefani/sucuri@ba687f782a37be0a1d7ff7e2d7a34c80d9bb6192 -
Branch / Tag:
refs/tags/v1.0.7 - Owner: https://github.com/marcosstefani
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@ba687f782a37be0a1d7ff7e2d7a34c80d9bb6192 -
Trigger Event:
push
-
Statement type: