{"id":7549,"library":"pybars3","title":"Pybars3","description":"Pybars3 is a Python library that provides a templating system compatible with Handlebars.js, supporting both Python 2 and Python 3. It is a fork of the original `pybars` project, enhancing it with Python 3 compatibility and features from Handlebars.js up to version 2.0. The current version is 0.9.7, released in November 2019, indicating an infrequent release cadence and a status of maintenance.","status":"maintenance","version":"0.9.7","language":"en","source_language":"en","source_url":"https://github.com/wbond/pybars3","tags":["templating","handlebars","python2","python3"],"install":[{"cmd":"pip install pybars3","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"note":"The main class for compiling Handlebars templates.","symbol":"Compiler","correct":"from pybars import Compiler"}],"quickstart":{"code":"from pybars import Compiler\n\n# Get a compiler\ncompiler = Compiler()\n\n# Define a helper function\ndef _list_helper(this, options, items):\n    result = ['<ul>']\n    for item in items:\n        result.append('<li>')\n        result.extend(options['fn'](item)) # Render the inner block\n        result.append('</li>')\n    result.append('</ul>')\n    return result\n\n# Register helpers and partials\nhelpers = {'list': _list_helper}\nheader_template = compiler.compile(u'<h1>{{title}}</h1>')\npartials = {'header': header_template}\n\n# Compile the main template source\nsource = u\"\"\"\n{{>header}}\n<p>Hello, {{name}}!</p>\n{{#list people}}{{firstName}} {{lastName}}{{/list}}\n\"\"\"\ntemplate = compiler.compile(source)\n\n# Data to render\ndata = {\n    'title': 'People List',\n    'name': 'World',\n    'people': [\n        {'firstName': 'Yehuda', 'lastName': 'Katz'},\n        {'firstName': 'Carl', 'lastName': 'Lerche'},\n        {'firstName': 'Alan', 'lastName': 'Johnson'}\n    ]\n}\n\n# Render the template\noutput = template(data, helpers=helpers, partials=partials)\nprint(output)","lang":"python","description":"This quickstart demonstrates compiling a Handlebars template, registering a custom block helper, defining a partial, and rendering the template with contextual data. Note the use of `u\"\"` for template strings for compatibility, though on Python 3 plain strings are sufficient."},"warnings":[{"fix":"Consult the `pybars3` GitHub README for a partial list of supported Handlebars.js features to confirm functionality. If a feature is missing, consider implementing it as a custom helper.","message":"Pybars3 does not fully implement all features of Handlebars.js 2.0 or even 1.1. Specific features like `@root`, `_parent`, `../` accessors, `each` helper with `@index`, `@key`, `@first`, `@last`, dynamic partials, and raw blocks are supported, but full compatibility with the latest Handlebars.js features should not be assumed.","severity":"gotcha","affected_versions":"<=0.9.7"},{"fix":"Ensure your Python helper functions adhere to the specified argument signatures: `def my_block_helper(this, options, arg1, kwarg1='val'): ...` for block helpers, and `def my_helper(this, arg1, kwarg1='val'): ...` for other helpers.","message":"Custom helper functions in Pybars3 have different calling conventions than their JavaScript counterparts. Block helpers must accept `this, options, *args, **kwargs`. Other helpers and closures in the context should accept `this, *args, **kwargs`.","severity":"gotcha","affected_versions":"All"},{"fix":"Avoid using Python reserved keywords as names for keyword arguments in your Handlebars templates when they are processed by Pybars3. Choose alternative names that are valid Python identifiers.","message":"When passing keyword arguments to helpers (e.g., `{{foo bar quux=1}}`), the keyword names in Handlebars templates must not be Python reserved words. Using a reserved word like `print` as a keyword argument name will result in a Python syntax error.","severity":"gotcha","affected_versions":"All"},{"fix":"Be mindful of the return type of your helpers. If you need to output unescaped HTML, return a `strlist`. For content that should be HTML-escaped by the template engine, return a standard Python string (or `unicode` in Python 2).","message":"For efficiency and control over HTML escaping, Pybars3 uses a `strlist` class. When a helper returns a `strlist` instance, its content will NOT be escaped, similar to Handlebars.js `SafeString`. Helpers in inner loops are recommended to return `list` or `strlist` for performance.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure your template source string is a Unicode string. In Python 2, use `u\"your template here\"`. In Python 3, all standard string literals are Unicode, but verify no byte strings (`b\"\"`) are being used as template input.","cause":"This error occurs when the template source provided to `compiler.compile()` is not a Unicode string. This is particularly common in Python 2 environments if string literals are not explicitly marked with `u''` or if byte strings are passed. In Python 3, it can happen if byte strings are inadvertently passed.","error":"PybarsError: Template source must be a unicode string"},{"fix":"Ensure the data context passed to the template matches the structure expected by the template. If accessing dictionary keys, ensure the context is a dictionary. Upgrade to Pybars3 0.9.2 or later, which improved the precedence of dictionary calls over attributes and `.get()` methods.","cause":"This error can occur within templates or helpers when attempting to access properties of a context variable that is a simple string, but the template expects an object (like a dictionary or an object with attributes). Older versions of Pybars3 (prior to 0.9.2) had issues where dictionary calls did not always take precedence over attributes, leading to unexpected resolution.","error":"AttributeError: 'str' object has no attribute 'get'"},{"fix":"Verify that your block helper's signature includes `options` as the second positional argument and that you are correctly invoking the inner block using `options['fn'](scope_for_inner_block)`. For example: `result.extend(options['fn'](item))`.","cause":"This typically happens in a custom block helper when `options['fn']` (which represents the inner block of the Handlebars helper) is not correctly invoked. It might be due to a missing `options` argument in the helper definition or calling `options.fn` instead of `options['fn']`.","error":"TypeError: 'list' object is not callable (when using options['fn'])"}]}