{"id":21037436,"url":"https://github.com/vintasoftware/python-handlebars","last_synced_at":"2026-02-17T21:32:28.112Z","repository":{"id":250347592,"uuid":"834228770","full_name":"vintasoftware/python-handlebars","owner":"vintasoftware","description":"Handlebars.js templating for Python 3","archived":false,"fork":false,"pushed_at":"2024-07-30T15:50:13.000Z","size":40,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-10-19T22:14:42.307Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vintasoftware.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-07-26T17:51:07.000Z","updated_at":"2025-07-28T09:36:08.000Z","dependencies_parsed_at":"2025-10-19T14:40:00.796Z","dependency_job_id":null,"html_url":"https://github.com/vintasoftware/python-handlebars","commit_stats":null,"previous_names":["vintasoftware/python-handlebars"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vintasoftware/python-handlebars","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vintasoftware%2Fpython-handlebars","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vintasoftware%2Fpython-handlebars/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vintasoftware%2Fpython-handlebars/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vintasoftware%2Fpython-handlebars/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vintasoftware","download_url":"https://codeload.github.com/vintasoftware/python-handlebars/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vintasoftware%2Fpython-handlebars/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29558501,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T20:52:40.164Z","status":"ssl_error","status_checked_at":"2026-02-17T20:48:10.325Z","response_time":100,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T13:26:13.916Z","updated_at":"2026-02-17T21:32:23.096Z","avatar_url":"https://github.com/vintasoftware.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# python-handlebars - Handlebars.js for Python 3\n\nPython-handlebars provides a template system for Python which is compatible with\nHandlebars.js. It is a fork of the handlebars project that adds Python 3\ncompatibility and numerous features from Handlebars.js 2.0.\n\nThis project is strongly inspired in [Pybars3](https://github.com/wbond/pybars3).\n\n## Installation\n\n```bash\npip install python-handlebars\n```\n\n## Handlebars.js Compatibility\n\nThis is somewhat of a side-project for the current developers, and is\nmaintained for almost purely pragmatic reasons. Being able to share templates\nbetween the server and client-side is very useful, and we like having something\nmore powerful than Mustache.\n\nSo, with that information, you should realize that the code is probably messy,\nthat there are certainly bugs and not all of Handlebars 2.0, or even 1.1 is\ncurrently implemented.\n\nHere is a partial list of features that are supported:\n\n- `@root` root data accesor (Handlebars 2.0)\n- `@_parent` parent scope accesor (Handlebars 2.0)\n- `../` parent scope accessor\n- `@index`, `@key` (Handlebars 1.0, 1.2)\n- `@first` and `@last` data element in the `#each` helper (Handlebars 1.1)\n- kwargs passed to partials (Handlebars 2.0)\n- `@../index` syntax for accessing parent scope data items (Handlebars 2.0)\n- `{{[segment literal notation]}}` for paths that contain non-word chars (Handlebars 1.1)\n- `{{\u003e \"quoted partial name\"}}` for partials that contain non-word chars (Handlebars 1.1)\n- `lookup` helper for dynamic name access (Handlebars 2.0)\n- Subexpresions (Handlebars 1.3)\n- Lines containing only block statements and whitespace are removed (Handlebars 2.0)\n- `handlebars.Compiler().precompile()` that is equivalent to `Handlebars.precompile()`\n- `{{\u003e (whichPartial) }}` dynamic partials (Handlebars 3.0)\n- `{{{{raw}}}}{{escaped}}{{{{/raw}}}}` raw blocks (Handlebars 2.0)\n- Whitespace control, `{{var~}}` (Handlebars 1.1)\n\nFeel free to jump in with issues or pull requests.\n\n## Usage\n\nFor details on the template language see the http://handlebarsjs.com\ndocumentation.\n\nTypical usage:\n\n```python\n# Get a compiler\nfrom handlebars import Compiler\ncompiler = Compiler()\n\n# Compile the template\nsource = u\"{{\u003eheader}}{{#list people}}{{firstName}} {{lastName}}{{/list}}\"\ntemplate = compiler.compile(source)\n\n# Add any special helpers\ndef _list(this, options, items):\n    result = [u'\u003cul\u003e']\n    for thing in items:\n        result.append(u'\u003cli\u003e')\n        result.extend(options['fn'](thing))\n        result.append(u'\u003c/li\u003e')\n    result.append(u'\u003c/ul\u003e')\n    return result\nhelpers = {'list': _list}\n\n# Add partials\nheader = compiler.compile(u'\u003ch1\u003ePeople\u003c/h1\u003e')\npartials = {'header': header}\n\n# Render the template\noutput = template({\n    'people': [\n        {'firstName': \"Yehuda\", 'lastName': \"Katz\"},\n        {'firstName': \"Carl\", 'lastName': \"Lerche\"},\n        {'firstName': \"Alan\", 'lastName': \"Johnson\"}\n    ]}, helpers=helpers, partials=partials)\n\nprint(output)\n```\n\nThe generated output will be:\n\n```html\n\u003ch1\u003ePeople\u003c/h1\u003e\u003cul\u003e\u003cli\u003eYehuda Katz\u003c/li\u003e\u003cli\u003eCarl Lerche\u003c/li\u003e\u003cli\u003eAlan Johnson\u003c/li\u003e\u003c/ul\u003e\n```\n\n### Handlers\n\nTranslating the engine to python required slightly different calling\nconventions to the JS version:\n\n* block helpers should accept `this, options, *args, **kwargs`\n* other helpers should accept `this, *args, **kwargs`\n* closures in the context should accept `this, *args, **kwargs`\n\nA template like `{{foo bar quux=1}}` will pass `bar` as a positional argument and\n`quux` as a keyword argument. Keyword arguments have to be non-reserved words in\nPython. For instance, `print` as a keyword argument will fail.\n\n## Implementation Notes\n\nTemplates with literal boolean arguments like `{{foo true}}` will have the\nargument mapped to Python's `True` or `False` as appropriate.\n\nFor efficiency, rather that passing strings round, handlebars passes a subclass of\nlist (`strlist`) which has a `__unicode__` implementation that returns\n`u\"\".join(self)`. Template helpers can return any of `list`, `tuple`, `unicode` or\n`strlist` instances. `strlist` exists to avoid quadratic overheads in string\nprocessing during template rendering. Helpers that are in inner loops *should*\nreturn `list` or `strlist` for the same reason.\n\n**NOTE** The `strlist` takes the position of SafeString in the js implementation:\nwhen returning a strlist it will not be escaped, even in a regular `{{}}`\nexpansion.\n\n```python\nimport handlebars\n\nsource = u\"{{bold name}}\"\n\ncompiler = handlebars.Compiler()\ntemplate = compiler.compile(source)\n\ndef _bold(this, name):\n    return handlebars.strlist(['\u003cstrong\u003e', name, '\u003c/strong\u003e'])\nhelpers = {'bold': _bold}\n\noutput = template({'name': 'Will'}, helpers=helpers)\nprint(output)\n```\n\nThe `data` facility from the JS implementation has not been ported at this\npoint, if there is demand for it it would be quite easy to add. Similarly\nthe `stringParams` feature has not been ported - quote anything you wish to force\nto a string in a helper call.\n\n## Dependencies\n\n* Python 3.8+\n* Python-OMeta\n\n## Development\n\nRunning tests:\n\n```bash\npython tests.py\n```\n\nTo display the AST and generated Python code, execute:\n\n```bash\npython tests.py --debug\n```\n\nTo run a specific test:\n\n```bash\npython tests.py TestAcceptance.test_subexpression\n```\n\nOr to debug a specific test:\n\n```bash\npython tests.py --debug TestAcceptance.test_subexpression\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvintasoftware%2Fpython-handlebars","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvintasoftware%2Fpython-handlebars","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvintasoftware%2Fpython-handlebars/lists"}