{"id":16545524,"url":"https://github.com/basxsoftwareassociation/htmlgenerator","last_synced_at":"2026-04-06T09:27:18.545Z","repository":{"id":45085438,"uuid":"314129620","full_name":"basxsoftwareassociation/htmlgenerator","owner":"basxsoftwareassociation","description":"TL;DR DOM on the server-side","archived":false,"fork":false,"pushed_at":"2024-12-24T04:35:45.000Z","size":1055,"stargazers_count":42,"open_issues_count":1,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-10-27T16:07:17.582Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/basxsoftwareassociation.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2020-11-19T03:49:14.000Z","updated_at":"2025-10-24T19:36:59.000Z","dependencies_parsed_at":"2023-12-21T09:52:19.048Z","dependency_job_id":"7f6cbaab-8794-493f-95a3-a78f7a7ebd76","html_url":"https://github.com/basxsoftwareassociation/htmlgenerator","commit_stats":{"total_commits":265,"total_committers":3,"mean_commits":88.33333333333333,"dds":0.1433962264150943,"last_synced_commit":"7218bca42ac882f0d4ce90bd8e25abf2cd8cd944"},"previous_names":[],"tags_count":68,"template":false,"template_full_name":null,"purl":"pkg:github/basxsoftwareassociation/htmlgenerator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basxsoftwareassociation%2Fhtmlgenerator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basxsoftwareassociation%2Fhtmlgenerator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basxsoftwareassociation%2Fhtmlgenerator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basxsoftwareassociation%2Fhtmlgenerator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/basxsoftwareassociation","download_url":"https://codeload.github.com/basxsoftwareassociation/htmlgenerator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basxsoftwareassociation%2Fhtmlgenerator/sbom","scorecard":{"id":227141,"data":{"date":"2025-08-11","repo":{"name":"github.com/basxsoftwareassociation/htmlgenerator","commit":"6a63d359303cbc57ad971bd55112aa14c6f7e871"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/automated_release.yml:1","Warn: no topLevel permission defined: .github/workflows/main.yml:1","Warn: no topLevel permission defined: .github/workflows/python-publish.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/automated_release.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/automated_release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/automated_release.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/automated_release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/automated_release.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/automated_release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/python-publish.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/basxsoftwareassociation/htmlgenerator/python-publish.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/automated_release.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/automated_release.yml:33","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/main.yml:26","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:23","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:24","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   7 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T04:00:52.927Z","repository_id":45085438,"created_at":"2025-08-17T04:00:52.927Z","updated_at":"2025-08-17T04:00:52.927Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31466436,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T08:36:52.050Z","status":"ssl_error","status_checked_at":"2026-04-06T08:36:51.267Z","response_time":112,"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-10-11T19:07:03.995Z","updated_at":"2026-04-06T09:27:18.526Z","avatar_url":"https://github.com/basxsoftwareassociation.png","language":"HTML","funding_links":[],"categories":["Libraries"],"sub_categories":["General HTML Generation"],"readme":"# HTML Generator\n\nA python package to generate HTML from a template which is defined through a tree of render-elements.\n\n## Why\n\n- **Guaranteed correct markup**: Don't worry about correct markup-structure anymore, never again count closing divs or get upset about a missing slash.\n- **Code formatting included** (if you format your Python code): Don't worry what would be the correct and most consistent way of formatting your HTML, never again search desperately for a Django-template-language-formatter for your IDE. (:heart: black).\n- **Easily generate and modify any template**: Don't worry about overwritting 3rd-party html templates just to change a single letter anymore, never again cramp your templates with an infinite number of `{% if feat %}`-statements trying to cover all possible use cases.\n\n- **Generate HTML in the same manner that you write Python code**: Use functions to generate parameterized html objects or build a custom declarativ-like system to compose output\n- **Keep the advantages of lazy rendering**: Render contexts and lazy values allow for implicit dependencies, like traditional templates.\n- **Define your own components**: Subclassing the base elements allows for easy implementation of e.g. a custom design or layout system.\n\nFor more in depth reasoning and thoughts check out this great articel: https://www.devever.net/~hl/stringtemplates\n\n## Getting started\n\nInstalling:\n\n    pip install htmlgenerator\n\nA simple example:\n\n```python\nimport htmlgenerator as hg\n\nmy_page = hg.HTML(hg.HEAD(), hg.BODY(hg.H1(\"It works!\")), doctype=True)\n\nprint(hg.render(my_page, {}))\n```\n\nThis will print the following HTML-document:\n\n```hmtl\n\u003c!DOCTYPE html\u003e\u003chtml \u003e\u003chead \u003e\u003cmeta charset=\"utf-8\" /\u003e\u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\u003c/head\u003e\u003cbody \u003e\u003ch1 \u003eIt works!\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e\n```\n\nNote that the provided implementation of the HTML tag and the HEAD tag come with sensible defaults for DOCTYPE and META tags.\n\n## HTML elements\n\nThe package `htmlgenerator` defines all standard HTML tags with uppercase classnames, e.g. BODY, DIV, SECTION, etc.\nThe **init** method of HTML elements will treat all passed arguments as child elements and keyword arguments as attributes on the HTML element. Leading underscores of attribute names will be removed (to allow _class_ and _for_ attributes to be specified) and underscores will be replaced by dashes because python does not allow identifiers to have a dash and HTML attributes normally do not use underscores.\n\nExample:\n\n```python\nfrom htmlgenerator import render, DIV, OL, LI\n\nprint(\n    render(\n        DIV(\n            \"My list is:\",\n            OL(\n                LI(\"not very long\"),\n                LI(\"having a good time\"),\n                LI(\"rendered with htmlgenerator\"),\n                LI(\"ending with this item\"),\n            ),\n        ),\n        {},\n    )\n)\nprint(\n    render(\n        DIV(\n            \"Hello world!\",\n            _class=\"success-message\",\n            style=\"font-size: 2rem\",\n            data_status=\"ok\",\n        ),\n        {},\n    )\n)\n```\n\nOutput:\n\n```hmtl\n\u003cdiv class=\"success-message\" style=\"font-size: 2rem\" data-status=\"ok\"\u003eHello world!\u003c/div\u003e\n\u003cdiv\u003eMy list is:\u003col\u003e\u003cli\u003enot very long\u003c/li\u003e\u003cli\u003ehaving a good time\u003c/li\u003e\u003cli\u003erendered with htmlgenerator\u003c/li\u003e\u003cli\u003eending with this item\u003c/li\u003e\u003c/ol\u003e\u003c/div\u003e\n```\n\n## Rendering\n\nThe method `htmlgenerator.render` should be used to render an element tree. All nodes in the tree should inherit from `htmlgenerator.BaseElement`. Leaves in the tree can be arbitrary python objects. The render function expects the root element of the tree and a context dictionary as arguments.\nThe output is generated by rendering the tree recursively. If an object in the tree is an instance of `BaseElement` its render method will be called with the context as single argument and it must return a generator which yields objects of type `str`. Otherwise the object will be converted to a string and escaped for use in HTML. In order to prevent a string from beeing escaped `htmlgenerator.mark_safe` or `django.utils.html.mark_safe` from the django package can be used.\n\nExample python object:\n\n```python\nimport datetime\nfrom htmlgenerator import render, DIV\n\nprint(render(DIV(\"Hello, here is some date: \", datetime.date.today()), {}))\nprint(\n    render(\n        DIV(\n            \"Hello, here is some data: \",\n            {\"fingers\": [1, 2, 3, 4, 5], \"stuff\": {\"set\": {1, 2, 3, 3, 3, 3, 3}}},\n        ),\n        {},\n    )\n)\n```\n\nOutput:\n\n```hmtl\n\u003cdiv\u003eHello, here is some date: 2020-11-20\u003c/div\u003e\n\u003cdiv\u003eHello, here is some data: {\u0026#x27;fingers\u0026#x27;: [1, 2, 3, 4, 5], \u0026#x27;stuff\u0026#x27;: {\u0026#x27;set\u0026#x27;: {1, 2, 3}}}\u003c/div\u003e\n```\n\nExample render object:\n\n```python\nfrom htmlgenerator import render, DIV\n\n\nclass DoStuff:\n    # be aware that all yielded strings will not be separated by spaces but concatenated directly\n    def render(self, context):\n        yield \"eat \"\n        yield \"sleep \"\n        yield \"program\"\n\n\nprint(render(DIV(\"I like to \", DoStuff()), {}))\n```\n\nOutput:\n\n```hmtl\n\u003cdiv\u003eI like to eat sleep program\u003c/div\u003e\n```\n\nExample escaping:\n\n```python\nfrom htmlgenerator import mark_safe, render, DIV\n\nprint(\n    render(\n        DIV(\n            \"Hello, here is some HTML: \",\n            '\u003cdiv style=\"font-size: 2rem\"\u003eHello world!\u003c/div\u003e',\n        ),\n        {},\n    )\n)\nprint(\n    render(\n        DIV(\n            \"Hello, here is NOT some HTML: \",\n            mark_safe('\u003cdiv style=\"font-size: 2rem\"\u003eHello world!\u003c/div\u003e'),\n        ),\n        {},\n    )\n)\n```\n\nOutput:\n\n```hmtl\n\u003cdiv\u003eHello, here is some HTML: \u0026lt;div style=\u0026quot;font-size: 2rem\u0026quot;\u0026gt;Hello world!\u0026lt;/div\u0026gt;\u003c/div\u003e\n\u003cdiv\u003eHello, here is NOT some HTML: \u003cdiv style=\"font-size: 2rem\"\u003eHello world!\u003c/div\u003e\u003c/div\u003e\n```\n\n## Lazy values\n\nIn order to allow rendering values which are not yet known at construction time but only at render time lazy values can be used.\nBy default htmlgenerator comes with the following lazy values:\n\n- `htmlgenerator.ContextFunction`: Calls a function with the context as argument and renders the returned value (shortcut `htmlgenerator.F`)\n- `htmlgenerator.ContextValue`: Renders a variable from the context, can use . to access nested attributes or dictionary keys (shortcut `htmlgenerator.C`)\n\nA lazy value will be resolved just before it is rendered. Custom implementations of lazy values can be added by inheriting from `htmlgenerator.Lazy`.\n\nExample:\n\n```python\nfrom htmlgenerator import render, DIV, C, F, ATTR\n\nprint(\n    render(\n        DIV(\"Hello, \", C(\"person.name\")),\n        {\"person\": {\"name\": \"Alice\", \"occupation\": \"Writer\"}},\n    )\n)\nprint(render(DIV(\"Crazy calculation: 4 + 2 = \", F(lambda context: 4 + 2)), {}))\n```\n\nOutput:\n\n```hmtl\n\u003cdiv\u003eHello, Alice\u003c/div\u003e\n\u003cdiv\u003eCrazy calculation: 4 + 2 = 6\u003c/div\u003e\n\u003cdiv\u003eThis text is wrapped inside a div element\u003c/div\u003e\n```\n\n## Virtual elements\n\nIn order to allow the building of a dynamic page virtual elements need to be used. The following virtual elements exist:\n\n- `htmlgenerator.BaseElement`: The base for all elements, can also be used to group elements without generating output by itself\n- `htmlgenerator.If`: Lazy evaluates the first argument at render time and returns the first child on true and the second child on false\n- `htmlgenerator.Iterator`: Takes an iterator which can be a lazy value and renders the child element for each iteration\n- `htmlgenerator.Fragment`: Allows to name a part of the tree which can then selectively be rendered by setting the `fragment` parameter when calling `hg.render` (inspired by https://htmx.org/essays/template-fragments/)\n\nExample:\n\n```python\nfrom htmlgenerator import render, SPAN, BaseElement, If, C, Iterator, Fragment, DIV, BODY\n\nprint(\n    render(BaseElement(\"Just\", SPAN(\"some\"), \"elements\", SPAN(\"without\"), \"parent\"), {})\n)\nprint(render(If(C(\"cold\"), \"It is cold\", \"It is not cold\"), {\"cold\": True}))\nprint(render(If(C(\"cold\"), \"It is cold\", \"It is not cold\"), {\"cold\": False}))\nprint(render(Iterator(range(7), SPAN(\"I love loops \")), {}))\n\nprint(render(BODY(\"HTML body\", Fragment(\"content\", DIV(\"Content of my page\"))), {}))\nprint(render(BODY(\"HTML body\", Fragment(\"content\", DIV(\"Content of my page\"))), {}, fragment=\"content\"))\n```\n\nOutput:\n\n```hmtl\nJust\u003cspan\u003esome\u003c/span\u003eelements\u003cspan\u003ewithout\u003c/span\u003eparent\nIt is cold\nIt is not cold\n\u003cspan\u003eI love loops \u003c/span\u003e\u003cspan\u003eI love loops \u003c/span\u003e\u003cspan\u003eI love loops \u003c/span\u003e\u003cspan\u003eI love loops \u003c/span\u003e\u003cspan\u003eI love loops \u003c/span\u003e\u003cspan\u003eI love loops \u003c/span\u003e\u003cspan\u003eI love loops \u003c/span\u003e\n\n\u003cbody\u003eHTML body\u003cdiv\u003eContent of my page\u003c/div\u003e\u003c/body\u003e\n\u003cdiv\u003eContent of my page\u003c/div\u003e\n```\n\n## Converting existing HTML source\n\nhtmlgenerator comes with a handy commandline tool to convert existing HTML-code into htmlgenerator python objects.\nIn order to get all the dependencies for the tool, install it with `pip install htmlgenerator[all]`\n\nIt can be used with standard input or with a list of files as arguments:\n\n    echo '\u003cdiv class=\"btn\" style=\"padding: 2rem\"\u003eClick me\u003c/div\u003e' | convertfromhtml \u003e mytemplate.py\n\n    convertfromhtml template1.html template2.html # will result in template1.html.py and template2.html.py\n\nBy default the generated python files are formatted with black.\nPython code which has been generated from very large files, e.g. complete websites, might take multiple minutes to be formated.\nIn order to get unformatted but still valid python code add the flag `--no-formatting`.\nThis will not run black on the generated python code and therefore be very fast.\nIn order to generate more compact code the flag `--compact` can be passed to `convertfromhtml`.\nThis will generate the most compact python code and works with and without `--no-formatting`.\nIn order to get human readable code the flag `--compact` is recommended.\nIn order to get code fast (especially for big pages) the flag `--no-formatting` is recommended.\nIn order to get a one-liner use `--compact` and `--no-formatting`.\n\n_Notes regarding the encoding of the input file:_\n\nIn case the encoding of the input HTML source file differs from the default\nencoding of the operating system, there is the flag `--encoding \u003cencoding\u003e`\nwhich allows to enforce the given encoding when reading the file. This is\nlikely the case on Windows systems. It is therefore recommended to use\n`--encoding utf8` when using `convertfromhtml` on windows.\n\n## Django integration\n\nIn order to use the element tree renderer in django html templates it is necessary to add a template tag which calls the render function.\n\n```python\n@register.simple_tag(takes_context=True)\ndef render_document(context, root):\n    return mark_safe(layout.render(root, context.flatten()))\n```\n\nThe render method of any object may also be directly passed to a HttpResponse object. This is useful if htmlgenerator should generate the complete page in function based views.\n\nExample of a helper function to render an element tree to a response (layout is the element tree):\n\n```python\nfrom django.http import HttpResponse\n\n\ndef render_layout_to_response(request, layout, context):\n    return HttpResponse(layout.render(context))\n```\n\n## Rational\n\nNotes:\n\n- Want internal/embeded DSL, access to document object model, not string interpolation\n- https://wiki.python.org/moin/Templating ==\u003e All dead links\n- Existing HTML-DSL have no support for more abstract concepts like iterators and lazy values\n  - https://github.com/duyixian1234/html_dsl\n  - https://github.com/benwbooth/python-teacup\n- We want something inspired by FRP (Functional reactive programming) and LISP like XAML (but without XML) or React/Vue (but not on the client-side)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasxsoftwareassociation%2Fhtmlgenerator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbasxsoftwareassociation%2Fhtmlgenerator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasxsoftwareassociation%2Fhtmlgenerator/lists"}