### Complete Pongo2 Web Application Example Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md A full Go web application demonstrating Pongo2 template setup, including loader, options, global variables, helper functions, sandbox restrictions, and request handling. ```go package main import ( "log" "net/http" "time" "github.com/flosch/pongo2/v7" ) var templates *pongo2.TemplateSet func init() { // Create loader loader := pongo2.MustNewLocalFileSystemLoader("./templates") // Create template set templates = pongo2.NewSet("web", loader) // Configure options templates.Options.TrimBlocks = true templates.Options.LStripBlocks = true // Set global variables templates.Globals["site_name"] = "My App" templates.Globals["current_year"] = time.Now().Year() // Helper functions templates.Globals["asset_url"] = func(path string) string { return "/static/" + path } // Sandbox restrictions templates.BanTag("ssi") templates.BanTag("include") // Force explicit template paths } func handler(w http.ResponseWriter, r *http.Request) { tpl, err := templates.FromCache("pages/home.html") if err != nil { http.Error(w, err.Error(), 500) return } err = tpl.ExecuteWriter(pongo2.Context{ "user": getCurrentUser(r), "items": getItems(), }, w) if err != nil { log.Printf("Template error: %v", err) } } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Hello World Example Source: https://github.com/flosch/pongo2/blob/master/docs/index.md A simple 'Hello World' example using pongo2's DefaultSet for basic template rendering. Ensure the 'fmt' package is imported for printing the output. ```go package main import ( "fmt" "github.com/flosch/pongo2/v7" ) func main() { // These functions use the DefaultSet (convenient for simple use cases) tpl, _ := pongo2.FromString("Hello {{ name }}!") out, _ := tpl.Execute(pongo2.Context{"name": "World"}) fmt.Println(out) // Hello World! } ``` -------------------------------- ### Install pongo2 Source: https://github.com/flosch/pongo2/blob/master/docs/index.md Use go get to install the pongo2 template engine. ```bash go get -u github.com/flosch/pongo2/v7 ``` -------------------------------- ### Reusable Filter Package Example Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md This example shows how to create a reusable filter package. Filters are registered in the init() function, and the package is imported for its side effects. ```go // filters/text.go package filters import ( "strings" "unicode" "github.com/flosch/pongo2/v7" ) func init() { pongo2.RegisterFilter("initials", filterInitials) pongo2.RegisterFilter("slugify", filterSlugify) pongo2.RegisterFilter("wordcount", filterWordCount) } // filterInitials extracts initials from a name. // Usage: {{ "John Doe"|initials }} -> "JD" func filterInitials(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { words := strings.Fields(in.String()) var initials strings.Builder for _, word := range words { if len(word) > 0 { initials.WriteRune(unicode.ToUpper(rune(word[0]))) } } return pongo2.AsValue(initials.String()), nil } // filterSlugify converts text to a URL-friendly slug. // Usage: {{ "Hello World!"|slugify }} -> "hello-world" func filterSlugify(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { s := strings.ToLower(in.String()) var result strings.Builder lastWasHyphen := true // Prevent leading hyphen for _, r := range s { if unicode.IsLetter(r) || unicode.IsDigit(r) { result.WriteRune(r) lastWasHyphen = false } else if !lastWasHyphen { result.WriteRune('-') lastWasHyphen = true } } slug := strings.TrimSuffix(result.String(), "-") return pongo2.AsValue(slug), nil } // filterWordCount counts the number of words in text. // Usage: {{ "Hello World"|wordcount }} -> 2 func filterWordCount(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { words := strings.Fields(in.String()) return pongo2.AsValue(len(words)), nil } ``` ```go // main.go package main import ( _ "myapp/filters" // Import for side effects (registers filters) "github.com/flosch/pongo2/v7" ) func main() { tpl := pongo2.Must(pongo2.FromString( "{{ name|initials }} {{ title|slugify }} {{ content|wordcount }} words ")) // ... } ``` -------------------------------- ### pongo2 Template Example Source: https://github.com/flosch/pongo2/blob/master/README.md A basic example demonstrating pongo2's template syntax, including macros, conditional logic, filters, and loops. This template renders user details and lists admins and members. ```django Our admins and users {# This is a short example to give you a quick overview of pongo2's syntax. #} {% macro user_details(user, is_admin=false) %}

= 40) || (user.karma > calc_avg_karma(userlist)+5) %} class="karma-good"{% endif %}> {{ user }}

This user registered {{ user.register_date|naturaltime }}.

The user's biography:

{{ user.biography|markdown|truncatewords_html:15 }} read more

{% if is_admin %}

This user is an admin!

{% endif %}
{% endmacro %}

Our admins

{% for admin in adminlist %} {{ user_details(admin, true) }} {% endfor %}

Our members

{% for user in userlist %} {{ user_details(user) }} {% endfor %} ``` -------------------------------- ### Quick Start: Compile and Execute a Template Source: https://github.com/flosch/pongo2/blob/master/LLM.txt Demonstrates the basic usage of pongo2 to compile a template string and execute it with a given context. Ensure the pongo2 library is imported. ```go import "github.com/flosch/pongo2/v7" // Compile and execute a template tpl, _ := pongo2.FromString("Hello {{ name|capfirst }}!") out, _ := tpl.Execute(pongo2.Context{"name": "world"}) // Output: Hello World! ``` -------------------------------- ### Matching a Specific Keyword Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Example of using `arguments.Match` to check for the presence of a specific keyword token, like 'as'. ```go if token := arguments.Match(pongo2.TokenKeyword, "as"); token != nil { // Found "as" keyword } ``` -------------------------------- ### Example pongo2 Template Source: https://github.com/flosch/pongo2/blob/master/docs/index.md A comprehensive example of a pongo2 template demonstrating inheritance, blocks, filters, conditional logic, loops, and includes. This template structure is compatible with Django syntax. ```django {% extends "base.html" %} {% block title %}{{ page.title }}{% endblock %} {% block content %}

{{ page.title|title }}

By {{ page.author.name }} on {{ page.date|date:"January 2, 2006" }}

{% if page.tags %} {% endif %}
{{ page.content|safe }}
{% include "comments.html" with post=page %} {% endblock %} ``` -------------------------------- ### Consume and Navigate Tokens Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Provides methods for inspecting and consuming tokens from the parser's argument list. Use Current() to peek, Consume() to get the next token, ConsumeN() for multiple, and Get() or GetR() for specific positions. ```go // Get current token without advancing current := arguments.Current() // Consume and return current token token := arguments.Consume() // Consume N tokens tokens := arguments.ConsumeN(3) // Get token at specific index token := arguments.Get(0) // First token // Get token from end (negative index) token := arguments.GetR(-1) // Last token // Check remaining token count if arguments.Remaining() > 0 { // More tokens to parse } // Get total token count count := arguments.Count() ``` -------------------------------- ### Serve HTTP Requests with Pongo2 Template Files Source: https://github.com/flosch/pongo2/blob/master/README.md This Go example shows how to pre-compile a Pongo2 template from a file at application startup using `pongo2.Must(pongo2.FromFile())` for efficiency. The template is then executed per HTTP request, writing the output directly to the ResponseWriter. ```go package main import ( "github.com/flosch/pongo2/v7" "net/http" ) var tplExample = pongo2.Must(pongo2.FromFile("example.html")) func examplePage(w http.ResponseWriter, r *http.Request) { err := tplExample.ExecuteWriter(pongo2.Context{"query": r.FormValue("query")}, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { http.HandleFunc("/", examplePage) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Creating a Secure Custom Template Set Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md For production applications, it's recommended to create a custom template set with appropriate security restrictions. This example shows how to use an embedded filesystem loader and ban specific tags and filters. ```go // For better security, create your own template set: loader := pongo2.NewFSLoader(embeddedFS) // Use embedded templates set := pongo2.NewSet("secure", loader) set.BanTag("include") // Restrict file inclusion set.BanTag("ssi") set.BanFilter("safe") // Prevent autoescape bypass ``` -------------------------------- ### Using FSLoader with Embedded Filesystem Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md This example shows how to use `FSLoader` with Go's `embed.FS` (Go 1.16+) to load templates from embedded files. It requires the `//go:embed` directive. ```go import "embed" //go:embed templates/* var templateFS embed.FS func main() { loader := pongo2.NewFSLoader(templateFS) set := pongo2.NewSet("embedded", loader) tpl, err := set.FromFile("templates/page.html") } ``` -------------------------------- ### Compile and Execute Pongo2 Template from String Source: https://github.com/flosch/pongo2/blob/master/README.md This example demonstrates how to compile a Pongo2 template directly from a string and then execute it with a given context. Ensure error handling for compilation and execution. ```go tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!") if err != nil { panic(err) } out, err := tpl.Execute(pongo2.Context{"name": "florian"}) if err != nil { panic(err) } fmt.Println(out) // Output: Hello Florian! ``` -------------------------------- ### Write Bytes to Template Output Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Example of writing byte data to the template output using the Write method of TemplateWriter. ```go func (node *myNode) Execute(ctx *ExecutionContext, writer TemplateWriter) error { data := []byte("binary data") writer.Write(data) return nil } ``` -------------------------------- ### Example Database Template Loader for Pongo2 Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md A custom `TemplateLoader` implementation that fetches template content from a SQL database. It uses the template name as the identifier and queries a 'templates' table. ```go type DBLoader struct { db *sql.DB } func (l *DBLoader) Abs(base, name string) string { return name // Templates are identified by name only } func (l *DBLoader) Get(path string) (io.Reader, error) { var content string err := l.db.QueryRow("SELECT content FROM templates WHERE name = ?", path).Scan(&content) if err != nil { return nil, err } return strings.NewReader(content), nil } ``` -------------------------------- ### Write String to Template Output Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Example of writing a simple string to the template output using the WriteString method of TemplateWriter. ```go func (node *myNode) Execute(ctx *ExecutionContext, writer TemplateWriter) error { writer.WriteString("Hello, World!") return nil } ``` -------------------------------- ### Handle Nil Values in Filters Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md Filters should gracefully handle nil input values. This example demonstrates returning an empty string when the input is nil. ```go func filterSafe(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { if in.IsNil() { return pongo2.AsValue(""), nil // Return empty string for nil } // ... rest of filter } ``` -------------------------------- ### Pongo2 Template Options Configuration Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Example of configuring template options per-test using `.tpl.options` files. Options like `TrimBlocks` and `LStripBlocks` affect template parsing and rendering. ```text TrimBlocks=true, LStripBlocks=true ``` -------------------------------- ### Render Template from File Source: https://github.com/flosch/pongo2/blob/master/docs/index.md Example of rendering a template directly from a file using pongo2's Must and FromFile functions. This method uses the DefaultSet and has unrestricted filesystem access. For production, consider using Template Sets for sandboxing. ```go // Using DefaultSet (simple, but has unrestricted filesystem access) tpl := pongo2.Must(pongo2.FromFile("templates/page.html")) err := tpl.ExecuteWriter(pongo2.Context{ "title": "My Page", "items": []string{"one", "two", "three"}, }, responseWriter) ``` -------------------------------- ### Loading Templates Relative to Base Directory Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md When a base directory is specified for `LocalFilesystemLoader`, all template paths are resolved relative to that directory. This example shows loading a template from a subdirectory. ```go loader := pongo2.MustNewLocalFileSystemLoader("/var/templates") set := pongo2.NewSet("web", loader) // Loads /var/templates/pages/home.html tpl, err := set.FromFile("pages/home.html") ``` -------------------------------- ### Matching One of Several Identifiers Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Example of using `arguments.MatchOne` to match an identifier token that can be one of several specified values, like 'asc' or 'desc'. ```go if token := arguments.MatchOne(pongo2.TokenIdentifier, "asc", "desc"); token != nil { direction := token.Val // "asc" or "desc" } ``` -------------------------------- ### Template Syntax: Tags Source: https://github.com/flosch/pongo2/blob/master/LLM.txt Provides examples of common control flow and structural tags in pongo2, such as conditional statements, loops, template inheritance, and macro definitions. ```django {% if condition %}...{% elif other %}...{% else %}...{% endif %} {% for item in items %}...{% empty %}...{% endfor %} {% block name %}...{% endblock %} {% extends "base.html" %} {% include "partial.html" %} {% macro name(args) %}...{% endmacro %} ``` -------------------------------- ### Custom Tag Development Best Practices Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Guidelines and examples for creating robust custom tags in Pongo2, including argument validation, context management, documentation, and edge case handling. ```APIDOC ## Custom Tag Development Best Practices ### 1. Validate Arguments Thoroughly Check all arguments at parse time to ensure correctness before execution. ```go func myTagParser(doc *pongo2.Parser, start *pongo2.Token, arguments *pongo2.Parser) (pongo2.INodeTag, error) { // Check for required arguments if arguments.Remaining() == 0 { return nil, arguments.Error("mytag requires at least one argument", nil) } // Parse and validate each argument // ... // Check for unexpected extra arguments if arguments.Remaining() > 0 { return nil, arguments.Error("unexpected extra arguments", nil) } return node, nil } ``` ### 2. Use Child Contexts for Scoped Variables Prevent variable leakage by using child execution contexts for tags that introduce local variables. ```go func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error { childCtx := pongo2.NewChildExecutionContext(ctx) childCtx.Private["local_var"] = value return node.wrapper.Execute(childCtx, writer) // local_var is not visible in parent context } ``` ### 3. Document Your Tags Include clear usage examples and argument descriptions in your tag documentation. ```go // TagCache caches rendered content for a specified duration. // // Usage: // {% cache "key" %}content{% endcache %} // {% cache key_var 300 %}content{% endcache %} // // Arguments: // - key: Cache key (string or expression) // - ttl: Optional TTL in seconds (default: 300) func tagCacheParser(...) { ... } ``` ### 4. Handle Edge Cases Consider and gracefully handle scenarios like empty content, nil values, and type mismatches during tag execution. ```go func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error { val, err := node.expr.Evaluate(ctx) if err != nil { return err } // Handle nil if val.IsNil() { return nil // Or write default content } // Handle wrong type gracefully if !val.CanSlice() { ctx.Logf("expected iterable, got %T", val.Interface()) return nil } // Handle empty collections if val.Len() == 0 { return nil // Nothing to iterate } // ... process items return nil } ``` ### 5. Clean Up Resources Ensure that any resources acquired by your tag are properly released after execution, typically using `defer`. ```go func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error { resource := acquireResource() defer resource.Release() return node.wrapper.Execute(ctx, writer) } ``` ``` -------------------------------- ### Sandbox Pongo2 by Banning Tags Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Restrict template functionality by banning specific tags before loading any templates. This example bans 'include', 'import', 'ssi', and 'extends'. ```go set := pongo2.NewSet("sandboxed", loader) // Ban potentially dangerous tags set.BanTag("include") // Prevent file inclusion set.BanTag("import") // Prevent macro imports from other files set.BanTag("ssi") // Prevent server-side includes set.BanTag("extends") // Prevent template inheritance // Now load templates - they can't use banned tags tpl, err := set.FromFile("user-template.html") ``` -------------------------------- ### Document Pongo2 Custom Tags Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Provide clear usage examples and argument descriptions in comments for custom tags. This aids users in understanding how to apply the tag correctly. ```go // TagCache caches rendered content for a specified duration. // // Usage: // {% cache "key" %}content{% endcache %} // {% cache key_var 300 %}content{% endcache %} // // Arguments: // - key: Cache key (string or expression) // - ttl: Optional TTL in seconds (default: 300) func tagCacheParser(...) { ... } ``` -------------------------------- ### Common Tasks: Custom Template Loader Source: https://github.com/flosch/pongo2/blob/master/LLM.txt Demonstrates how to implement a custom template loader in Go for pongo2 by defining the `Abs` and `Get` methods of the `TemplateLoader` interface. This allows loading templates from custom sources. ```go type MyLoader struct{} func (l *MyLoader) Abs(base, name string) string { return filepath.Join(filepath.Dir(base), name) } func (l *MyLoader) Get(path string) (io.Reader, error) { return os.Open(path) } set := pongo2.NewSet("my-set", &MyLoader{}) tpl, _ := set.FromFile("template.html") ``` -------------------------------- ### Django Template Syntax for Widget Tag Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Example of how to use the custom 'widget' tag in a Django template, passing named arguments for text, style, and disabled state. ```django {% widget "button" text="Click me" style="primary" disabled=false %} ``` -------------------------------- ### Implement Pongo2 TemplateLoader Interface Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md Define custom template loading logic by implementing the `TemplateLoader` interface, which requires `Abs` for path resolution and `Get` for retrieving template content. ```go type TemplateLoader interface { // Abs calculates the absolute path to a template // base is the parent template's path (for includes/extends) // name is the requested template name Abs(base, name string) string // Get returns a reader for the template content Get(path string) (io.Reader, error) } ``` -------------------------------- ### Internal DefaultSet Initialization Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md This code demonstrates the internal initialization process of the DefaultSet, including setting up the default loader and configuration. ```go DefaultLoader = MustNewLocalFileSystemLoader("") DefaultSet = NewSet("default", DefaultLoader) ``` -------------------------------- ### Initializing LocalFilesystemLoader Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md Demonstrates different ways to initialize a `LocalFilesystemLoader`, including specifying a base directory or using the current working directory. The `MustNewLocalFileSystemLoader` variant panics on error. ```go // Without base directory (uses working directory) loader, err := pongo2.NewLocalFileSystemLoader("") // With base directory loader, err := pongo2.NewLocalFileSystemLoader("/var/templates") // Panics on error (useful for init) loader := pongo2.MustNewLocalFileSystemLoader("/var/templates") ``` -------------------------------- ### Pongo2 Automatic HTML Escaping Example Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md By default, Pongo2 automatically escapes HTML special characters in variable output to prevent XSS attacks. This example shows how user input containing script tags is transformed. ```django {{ user_input }} ``` ```html <script>alert('xss')</script> ``` -------------------------------- ### Template Rendering from File with HTTP Server Source: https://context7.com/flosch/pongo2/llms.txt Load templates from the filesystem and pre-compile them at startup for performance. Execute templates directly to an http.ResponseWriter. ```go package main import ( "github.com/flosch/pongo2/v7" "net/http" ) // Pre-compile templates at startup using Must() helper var tplExample = pongo2.Must(pongo2.FromFile("templates/example.html")) func examplePage(w http.ResponseWriter, r *http.Request) { // Execute template directly to ResponseWriter err := tplExample.ExecuteWriter(pongo2.Context{ "query": r.FormValue("query"), "user": getCurrentUser(r), }, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { http.HandleFunc("/", examplePage) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Count Words in String Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md Use the `wordcount` filter to get the total number of words in a string. ```django {{ "Hello World"|wordcount }} ``` -------------------------------- ### Configure Template Loaders for Different Sources Source: https://context7.com/flosch/pongo2/llms.txt Set up template loading from local disk, embedded filesystems, or Go's `fs.FS` interface. Multiple loaders can be combined in a set, and new loaders can be added dynamically. ```go package main import ( "embed" "os" "github.com/flosch/pongo2/v7" ) //go:embed templates/* var embeddedTemplates embed.FS func main() { // LocalFilesystemLoader - load from disk fsLoader := pongo2.MustNewLocalFileSystemLoader("/var/templates") // FSLoader - load from Go's fs.FS interface (embed.FS, os.DirFS, etc.) embedLoader := pongo2.NewFSLoader(embeddedTemplates) dirLoader := pongo2.NewFSLoader(os.DirFS("/var/templates")) // Multiple loaders - tries each in order set := pongo2.NewSet("multi", fsLoader, embedLoader) set.AddLoader(dirLoader) // Add more loaders later // Template resolution tries loader1 first, then loader2, etc. tpl, err := set.FromFile("page.html") if err != nil { panic(err) } out, _ := tpl.Execute(pongo2.Context{}) println(out) } ``` -------------------------------- ### Render Template from File Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md Pre-compile templates from files at startup for better performance in web applications. Handle execution errors by returning an HTTP error. ```go package main import ( "github.com/flosch/pongo2/v7" "net/http" ) // Pre-compile templates at startup for better performance var tplExample = pongo2.Must(pongo2.FromFile("templates/example.html")) func examplePage(w http.ResponseWriter, r *http.Request) { err := tplExample.ExecuteWriter(pongo2.Context{ "query": r.FormValue("query"), }, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { http.HandleFunc("/", examplePage) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Creating and Configuring a Custom Template Set Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md This snippet shows how to create a new template set with a specific loader, configure its properties like debug mode and global variables, and then load a template from this set. ```go // Create a new set with a loader loader := pongo2.MustNewLocalFileSystemLoader("/path/to/templates") mySet := pongo2.NewSet("email-templates", loader) // Configure the set mySet.Debug = true mySet.Globals["company_name"] = "ACME Corp" // Load templates from this set tpl, err := mySet.FromFile("welcome.html") ``` -------------------------------- ### Check if Built-in Filter Exists Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md Provides an example of checking if a filter is registered as a built-in filter using the BuiltinFilterExists function. ```go if pongo2.BuiltinFilterExists("myfilter") { // Filter is available } ``` -------------------------------- ### Register a Custom Filter Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md Register a custom filter using `pongo2.RegisterFilter` within an `init()` function. This example registers a 'double' filter. ```go package main import "github.com/flosch/pongo2/v7" func init() { pongo2.RegisterFilter("double", filterDouble) } func filterDouble(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { return pongo2.AsValue(in.Integer() * 2), nil } ``` -------------------------------- ### Testing: Command Line Interface Source: https://github.com/flosch/pongo2/blob/master/LLM.txt Shows the basic commands for running tests and benchmarks for the pongo2 project using Go's built-in testing tools. ```bash # Run all tests go test ./... # Run specific test go test -run TestFilterEscape ./... # Run benchmarks go test -bench=. -benchmem ./... ``` -------------------------------- ### Convert String to List of Characters Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md Use the `make_list` filter to convert a string into a list where each element is a single character. This example iterates through the characters. ```django {% for char in "hello"|make_list %}{{ char }}-{% endfor %} ``` -------------------------------- ### Template Execution Methods Source: https://context7.com/flosch/pongo2/llms.txt Demonstrates various methods for executing templates, including returning strings, byte slices, writing to io.Writers (buffered and unbuffered), and executing specific blocks. ```go package main import ( "bytes" "fmt" "github.com/flosch/pongo2/v7" "os" ) func main() { tpl, _ := pongo2.FromString("Hello {{ name }}!") ctx := pongo2.Context{"name": "World"} // Returns rendered template as string out, _ := tpl.Execute(ctx) fmt.Println(out) // Returns rendered template as []byte bytesOut, _ := tpl.ExecuteBytes(ctx) fmt.Println(string(bytesOut)) // Writes to io.Writer (buffered, safe on error) var buf bytes.Buffer _ = tpl.ExecuteWriter(ctx, &buf) fmt.Println(buf.String()) // Writes to io.Writer (unbuffered, faster but partial output on error) _ = tpl.ExecuteWriterUnbuffered(ctx, os.Stdout) // Execute specific blocks only (for partial rendering) blockTpl, _ := pongo2.FromString(` {% block header %}Header Content{% endblock %} {% block content %}Main Content{% endblock %} {% block footer %}Footer Content{% endblock %} `) blocks, _ := blockTpl.ExecuteBlocks(ctx, []string{"header", "content"}) fmt.Println(blocks["header"]) // "Header Content" fmt.Println(blocks["content"]) // "Main Content" } ``` -------------------------------- ### Run Benchmarks in Go Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Execute all benchmarks in the current module and display memory allocation statistics. Use for performance analysis. ```bash go test -bench=. -benchmem ./... ``` -------------------------------- ### Split String into List Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md Use the `split` filter to divide a string into a list based on a delimiter. This example shows iterating over the resulting list. ```django {% for part in "a,b,c"|split:"," %}{{ part }}{% endfor %} ``` -------------------------------- ### Get a random element from a list Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md The `random` filter selects and returns a single, arbitrary element from a list. This is useful for displaying varied content. ```django {{ items|random }} ``` -------------------------------- ### Capture and Transform Output with Buffer Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Demonstrates capturing template output into a buffer, transforming it (e.g., to uppercase), and then writing the transformed content. ```go func (node *myNode) Execute(ctx *ExecutionContext, writer TemplateWriter) error { var buf bytes.Buffer // Execute wrapped content into buffer err := node.wrapper.Execute(ctx, &buf) if err != nil { return err } // Transform the captured content transformed := strings.ToUpper(buf.String()) // Write transformed content writer.WriteString(transformed) return nil } ``` -------------------------------- ### Basic Template Rendering from String Source: https://context7.com/flosch/pongo2/llms.txt Compile a template from a string and execute it with a context to produce output. Ensure error handling for compilation and execution. ```go package main import ( "fmt" "github.com/flosch/pongo2/v7" ) func main() { // Compile the template from a string tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!") if err != nil { panic(err) } // Execute with context - can be called multiple times out, err := tpl.Execute(pongo2.Context{"name": "florian"}) if err != nil { panic(err) } fmt.Println(out) // Output: Hello Florian! } ``` -------------------------------- ### Sandbox Pongo2 by Banning Filters Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Restrict template functionality by banning specific filters before loading any templates. This example bans the 'safe' and 'escapejs' filters. ```go set := pongo2.NewSet("restricted", loader) // Ban filters that bypass security set.BanFilter("safe") // Prevent bypassing autoescape // Ban filters based on your security requirements set.BanFilter("escapejs") // If you don't want JS output ``` -------------------------------- ### Peeking N Tokens Ahead Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Shows how to use `arguments.PeekN` to look ahead a specified number of tokens (e.g., 1 token ahead) to check for a specific type and value (e.g., '='). ```go if token := arguments.PeekN(1, pongo2.TokenSymbol, "="); token != nil { // Token after next is "=" } ``` -------------------------------- ### Template Filters Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md Transform variable output using filters. Examples include converting to uppercase, truncating words, formatting numbers, and joining elements. ```django {{ name|upper }} {{ text|truncatewords:30 }} {{ price|floatformat:2 }} {{ items|join:", " }} ``` -------------------------------- ### Macro Recursion Example Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Illustrates a macro that calls itself, which Pongo2 protects against by limiting recursion depth to prevent stack overflows. Exceeding the limit results in an error. ```django {% macro infinite() %} {{ infinite() }} {# This will eventually fail #} {% endmacro %} ``` -------------------------------- ### Load Template from Cache Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md Use `FromCache` to load templates, which improves performance by avoiding recompilation on each request. This is recommended for production environments. ```go tpl, err := pongo2.FromCache("templates/page.html") ``` -------------------------------- ### Peeking for a Specific Keyword and Value Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Shows how to use `arguments.Peek` to inspect the next token for a specific keyword and value ('as') without consuming it. ```go if token := arguments.Peek(pongo2.TokenKeyword, "as"); token != nil { // Next token is "as" (not consumed) } ``` -------------------------------- ### Get the length of a list or string Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md The `length` filter returns the number of elements in a list or the number of characters in a string. It's a fundamental filter for sequence manipulation. ```django {{ items|length }} ``` ```django {{ "hello"|length }} {# 5 #} ``` -------------------------------- ### Valid and Invalid Context Keys in Pongo2 Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Context keys must be valid identifiers. Invalid keys, such as those starting with quotes or containing hyphens/dots, will cause a panic. ```go // Valid ctx := pongo2.Context{ "user": user, "item_1": item, } // Invalid - will panic ctx := pongo2.Context{ "'invalid": value, // Can't start with quote "foo-bar": value, // Can't contain hyphen "foo.bar": value, // Can't contain dot } ``` -------------------------------- ### Compare Benchmarks with Benchstat Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Compare benchmark results using `benchstat`. This requires running benchmarks multiple times and saving the output to files for comparison. ```bash go test -bench=. -benchmem -count=10 > old.txt # make changes go test -bench=. -benchmem -count=10 > new.txt benchstat old.txt new.txt ``` -------------------------------- ### Render Template from String Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md Compile and execute a template directly from a string. Ensure error handling for compilation and execution. ```go package main import ( "fmt" "github.com/flosch/pongo2/v7" ) func main() { // Compile the template tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!") if err != nil { panic(err) } // Execute with context out, err := tpl.Execute(pongo2.Context{"name": "florian"}) if err != nil { panic(err) } fmt.Println(out) // Output: Hello Florian! } ``` -------------------------------- ### Matching a String Token Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Example of using `arguments.MatchType` to check if the next token is a string and retrieve its value. The value returned is the string content without the surrounding quotes. ```go if token := arguments.MatchType(pongo2.TokenString); token != nil { value := token.Val // The string content (without quotes) } ``` -------------------------------- ### Create Isolated Template Set Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Create a new `TemplateSet` for isolated template groups, shared globals, and sandboxing. Use `NewSet()` for distinct configurations. ```go NewSet() ``` -------------------------------- ### Macro Returning Safe String Source: https://github.com/flosch/pongo2/blob/master/docs/macros.md Macros return their rendered content as a safe string, meaning HTML is not escaped by default. This example shows a simple bold tag. ```django {% macro bold(text) %} {{ text }} {% endmacro %} {{ bold("Hello") }} {# Output: Hello #} ``` -------------------------------- ### Run All Tests in Go Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Execute all tests within the current Go module. Ensure all tests pass before committing. ```bash go test ./... ``` -------------------------------- ### Create Custom Pongo2 Template Set Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Avoid using the default convenience functions for production. Instead, create a custom template set with either an embedded filesystem loader for maximum security or a local filesystem loader with specific sandbox restrictions. ```go // Instead of using pongo2.FromFile() (which uses DefaultSet), do this: // Option 1: Use embedded templates (most secure) //go:embed templates/* var templateFS embed.FS loader := pongo2.NewFSLoader(templateFS) set := pongo2.NewSet("secure", loader) // Option 2: Use LocalFilesystemLoader with sandbox restrictions loader := pongo2.MustNewLocalFileSystemLoader("/var/templates") set := pongo2.NewSet("restricted", loader) set.BanTag("include") // Prevent file inclusion set.BanTag("import") // Prevent macro imports set.BanTag("ssi") // Prevent server-side includes set.BanTag("extends") // Prevent template inheritance set.BanFilter("safe") // Prevent autoescape bypass // Now use the custom set tpl, err := set.FromFile("page.html") ``` -------------------------------- ### Get the last element of a list or string Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md Use the `last` filter to retrieve the final element from a list or the last character of a string. This is helpful for accessing the end of a sequence. ```django {{ items|last }} ``` ```django {{ "hello"|last }} {# o #} ``` -------------------------------- ### Get the first element of a list or string Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md The `first` filter returns the initial element from a list or the first character of a string. It's useful for accessing the beginning of a sequence. ```django {{ items|first }} ``` ```django {{ "hello"|first }} {# h #} ``` -------------------------------- ### Run Tests with Verbose Output Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Execute tests and display detailed output for each test case. Helpful for understanding test execution flow. ```bash go test -v ./... ``` -------------------------------- ### Validate Filter Parameters Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md Always validate filter parameters to ensure they meet requirements. This example checks if a length parameter is provided and is non-negative, returning a *pongo2.Error if validation fails. ```go func filterTruncate(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) { if param.IsNil() { return nil, &pongo2.Error{ Sender: "filter:truncate", OrigError: errors.New("truncate requires a length parameter"), } } length := param.Integer() if length < 0 { return nil, &pongo2.Error{ Sender: "filter:truncate", OrigError: errors.New("length must be non-negative"), } } // ... rest of filter } ``` -------------------------------- ### Registering a Custom Tag Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Demonstrates how to register a new custom tag named 'mytag' with its corresponding parser function. Ensure the tag name is unique to avoid conflicts. ```go func init() { err := pongo2.RegisterTag("mytag", myTagParser) if err != nil { panic(err) // Tag name already exists } } ``` -------------------------------- ### Pongo2 Execution Flow Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Illustrates the Pongo2 template processing pipeline, from template string to final output. ```text Template String → Lexer → Tokens → Parser → AST (INode tree) → Execute → Output ``` -------------------------------- ### Lint Code with Golangci-Lint Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md Run `golangci-lint` for comprehensive code linting. This tool aggregates multiple linters to enforce style and catch potential issues. ```bash golangci-lint run ``` -------------------------------- ### LocalFileSystemLoader Path Resolution Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Demonstrates how LocalFileSystemLoader resolves paths. Note that the base directory is for path resolution only and not a security feature. Absolute paths bypass it. ```go // The base directory is for path resolution, NOT security loader := pongo2.MustNewLocalFileSystemLoader("/var/templates") set := pongo2.NewSet("app", loader) // Relative paths are resolved from the base directory tpl, _ := set.FromFile("pages/home.html") // Loads /var/templates/pages/home.html // WARNING: Absolute paths bypass the base directory entirely tpl, _ := set.FromFile("/etc/passwd") // This would work if not restricted! ``` -------------------------------- ### Matching One of Several Symbols Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Demonstrates using `arguments.MatchOne` to match a symbol token that can be one of several options, such as an opening parenthesis or bracket. ```go if token := arguments.MatchOne(pongo2.TokenSymbol, "(", "["); token != nil { opener := token.Val } ``` -------------------------------- ### Pongo2 Parser Argument Matching Methods Source: https://github.com/flosch/pongo2/blob/master/docs/custom-extensions.md Illustrates various methods available on the `arguments` parser for matching specific token types, keywords, identifiers, and expressions. Useful for defining custom tag syntax. ```go // Match specific token type and value if token := arguments.Match(pongo2.TokenKeyword, "as"); token != nil { // Matched "as" keyword } // Match any of several values if token := arguments.MatchOne(pongo2.TokenIdentifier, "asc", "desc"); token != nil { // Matched either "asc" or "desc" } // Match by type only if token := arguments.MatchType(pongo2.TokenString); token != nil { value := token.Val } if token := arguments.MatchType(pongo2.TokenNumber); token != nil { // ... } if token := arguments.MatchType(pongo2.TokenIdentifier); token != nil { name := token.Val } // Parse a full expression expr, err := arguments.ParseExpression() // Check remaining arguments if arguments.Remaining() > 0 { return nil, arguments.Error("Too many arguments", nil) } // Peek without consuming if arguments.Peek(pongo2.TokenSymbol, "=") != nil { // Next token is "=" } ``` -------------------------------- ### Extract a slice from a list Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md The `slice` filter extracts a portion of a list based on start and end indices, similar to Python's slicing. Negative indices count from the end. ```django {{ items|slice:":2" }} ``` ```django {{ items|slice:"1:" }} ``` ```django {{ items|slice:"1:3" }} ``` ```django {{ items|slice:"-2:" }} ``` -------------------------------- ### Basic Filter Usage Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md Demonstrates the basic syntax for applying filters to variables, including filters with and without arguments, and chaining multiple filters. ```django {{ value|filtername }} ``` ```django {{ value|filtername:argument }} ``` ```django {{ value|filter1|filter2|filter3 }} ``` -------------------------------- ### Macro Avoiding Context Access Source: https://github.com/flosch/pongo2/blob/master/docs/macros.md This example contrasts a macro that relies on implicit context (`bad_header`) with one that explicitly accepts arguments (`good_header`), highlighting the latter's improved reusability. ```django {# Avoid: Relies on implicit context #} {% macro bad_header() %}

{{ page_title }}

{% endmacro %} {# Better: Explicit argument #} {% macro good_header(title) %}

{{ title }}

{% endmacro %} {{ good_header(page_title) }} ``` -------------------------------- ### Creating Child Execution Contexts in Pongo2 Source: https://github.com/flosch/pongo2/blob/master/docs/custom-extensions.md Demonstrates how to create a new child execution context using `pongo2.NewChildExecutionContext` for tags that require their own variable scope, such as loops. ```go func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error { // Create child context (inherits parent's variables) childCtx := pongo2.NewChildExecutionContext(ctx) // Add scoped variables childCtx.Private["loop_var"] = someValue // Execute wrapped content with child context return node.wrapper.Execute(childCtx, writer) } ``` -------------------------------- ### Pongo2 Store Position for Error Reporting Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Best practice for custom Pongo2 tags: store the start token of the tag to provide accurate error reporting with line and column numbers. ```go type myTagNode struct { position *pongo2.Token // For error reporting // ... other fields } ``` -------------------------------- ### Common Tasks: Adding a Custom Filter Source: https://github.com/flosch/pongo2/blob/master/LLM.txt Provides a Go code example for registering a custom filter with pongo2. The filter function receives input and parameter values and returns a transformed value. ```go func init() { pongo2.RegisterFilter("myfilter", func(in, param *pongo2.Value) (*pongo2.Value, error) { // Transform in.String() and return new Value return pongo2.AsValue(result), nil }) } ``` -------------------------------- ### Tag Parser Function Signature Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md Defines the signature for a custom tag parser function, which receives the document parser, the starting token, and an argument parser. It returns a compiled tag node or an error. ```go func myTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, error) ``` -------------------------------- ### Custom Secure Loader Implementation Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md Implement a custom loader that enforces additional security restrictions, such as checking file extensions and ensuring paths stay within an allowed directory. ```go type SecureLoader struct { baseDir string allowedExt []string } func (l *SecureLoader) Abs(base, name string) string { // Resolve path relative to base directory resolved := filepath.Join(filepath.Dir(base), name) // Ensure result is within allowed directory if !strings.HasPrefix(resolved, l.baseDir) { return "" // Return empty to indicate not found } return resolved } func (l *SecureLoader) Get(path string) (io.Reader, error) { // Check file extension ext := filepath.Ext(path) allowed := false for _, e := range l.allowedExt { if ext == e { allowed = true break } } if !allowed { return nil, fmt.Errorf("file extension not allowed: %s", ext) } return os.Open(path) } ```