{"id":16105196,"url":"https://github.com/mikeckennedy/chameleon_partials","last_synced_at":"2025-08-19T11:09:43.496Z","repository":{"id":62561657,"uuid":"389730903","full_name":"mikeckennedy/chameleon_partials","owner":"mikeckennedy","description":"Simple reuse of partial HTML page templates in the Chameleon template language for Python web frameworks. #pypackage","archived":false,"fork":false,"pushed_at":"2024-01-21T21:43:21.000Z","size":2923,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-07T08:47:53.391Z","etag":null,"topics":["chameleon","html","pyramid","python","template-engine"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikeckennedy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["mikeckennedy"]}},"created_at":"2021-07-26T18:24:29.000Z","updated_at":"2025-06-24T18:22:53.000Z","dependencies_parsed_at":"2024-01-21T22:52:04.831Z","dependency_job_id":"d3531ec6-b4be-4720-a87e-be77408ed2ae","html_url":"https://github.com/mikeckennedy/chameleon_partials","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mikeckennedy/chameleon_partials","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Fchameleon_partials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Fchameleon_partials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Fchameleon_partials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Fchameleon_partials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikeckennedy","download_url":"https://codeload.github.com/mikeckennedy/chameleon_partials/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikeckennedy%2Fchameleon_partials/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270642676,"owners_count":24621325,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["chameleon","html","pyramid","python","template-engine"],"created_at":"2024-10-09T19:08:49.854Z","updated_at":"2025-08-19T11:09:43.470Z","avatar_url":"https://github.com/mikeckennedy.png","language":"Python","funding_links":["https://github.com/sponsors/mikeckennedy"],"categories":[],"sub_categories":[],"readme":"# Chameleon Partials\n\nSimple reuse of partial HTML page templates in the Chameleon template language for Python web frameworks.\n(There is also a [Jinja2/Flask version here](https://github.com/mikeckennedy/jinja_partials).)\n\n## Overview\n\nWhen building real-world web apps with Chameleon, it's easy to end up with repeated HTML fragments.\nJust like organizing code for reuse, it would be ideal to reuse smaller sections of HTML template code.\nThat's what this library is all about.\n\n## Example\n\nThis project comes with a sample Pyramid application (see the `example` folder). This app displays videos\nthat can be played on YouTube. The image, subtitle of author and view count are reused throughout the\napp. Here's a visual:\n\n![](https://raw.githubusercontent.com/mikeckennedy/chameleon_partials/main/readme_resources/reused-html-visual.png)\n\nCheck out the [**demo / example application**](https://github.com/mikeckennedy/chameleon_partials/tree/main/example) \nto see it in action. \n\n## Installation\n\nIt's just `pip install chameleon-partials` and you're all set with this pure Python package.\n\n## Usage\n\nUsing the library is incredible easy. The first step is to register the partial method with Chameleon.\nDo this once at app startup:\n\n```python\nfrom pathlib import Path\nimport chameleon_partials\n\ndef main(_, **settings):\n    \"\"\" This function returns a Pyramid WSGI application.\n    \"\"\"\n    with Configurator(settings=settings) as config:\n        config.include('pyramid_chameleon')\n        config.include('.routes')\n        config.scan()\n        \n        # Register the extension for working with Chameleon.\n        folder = (Path(__file__).parent / \"templates\").as_posix()\n        chameleon_partials.register_extensions(folder, auto_reload=True, cache_init=True)\n\n    return config.make_wsgi_app()\n```\n\nNext, you define your main HTML (Chameleon) templates as usual. Then \ndefine your partial templates. I recommend locating and naming them accordingly:\n\n```\n├── templates\n│   ├── errors\n│   │   └── 404.pt\n│   ├── home\n│   │   ├── index.pt\n│   │   └── listing.pt\n│   └── shared\n│       ├── _layout.pt\n│       └── partials\n│           ├── video_image.pt\n│           └── video_square.pt\n```\n\nNotice the `partials` subfolder in the `templates/shared` folder.\n\nThe templates are just HTML fragments. Here is a stand-alone one for the YouTube thumbnail from\nthe example app:\n\n```html\n\u003cimg src=\"https://img.youtube.com/vi/${ video.id }/maxresdefault.jpg\"\n     class=\"img img-responsive ${ ' '.join(classes or []) }\"\n     alt=\"${ video.title }\"\n     title=\"${ video.title }\"\u003e\n```\n\nNotice that an object called `video` and list of classes are passed in as the model.\n\nTemplates can also be nested. Here is the whole single video fragment with the image as well as other info\nlinking out to YouTube:\n\n```html\n\u003cdiv\u003e\n    \u003ca href=\"https://www.youtube.com/watch?v=${ video.id }\" target=\"_blank\"\u003e\n        ${ render_partial('shared/partials/video_image.pt', video=video, classes=[]) }\n    \u003c/a\u003e\n    \u003ca href=\"https://www.youtube.com/watch?v=${ video.id }\" target=\"_blank\"\n       class=\"author\"\u003e${ video.author }\u003c/a\u003e\n    \u003cdiv class=\"views\"\u003e${ \"{:,}\".format(video.views) } views\u003c/div\u003e\n\u003c/div\u003e\n```\n\nNow you see the `render_partial()` method. It takes the subpath into the templates folder and\nany model data passed in as keyword arguments.\n\nWe can finally generate the list of video blocks as follows:\n\n```html\n\u003cdiv class=\"video\" tal:repeat=\"v videos\"\u003e\n    ${ render_partial('shared/partials/video_square.pt', video=v) }\n\u003c/div\u003e\n```\n\nThis time, we reframe each item in the list from the outer template (called `v`) as the `video` model\nin the inner HTML section.\n\n## The View Methods\n\nIn order to share the `render_partial()` function with your template, you'll need to pass it along to the\ntemplate with your model (dictionary). \n\nIf you are using the **Pyramid web framework**, you can add this file as middleware. Just drop it into\nyour `views` folder:\n\n```python\n# views/partials_middleware.py\nfrom pyramid.events import subscriber, BeforeRender\n\nimport chameleon_partials\n\n\n@subscriber(BeforeRender)\ndef add_global(event):\n    event['render_partial'] = chameleon_partials.render_partial\n```\n\nFor other frameworks using Chameleon (e.g. FastAPI), you can append the render_partial to the\nresulting dictionary. We've built a simple function to keep this fool-proof: \n\n```python\nchameleon_partials.extend_model(model)\n```\n\nHere's a typical view method that uses `render_partial`, notice the use of extending the \nmodel before passing it to the view:\n\n```python\n@view_config(route_name='listing', renderer='demo_chameleon_partials:templates/home/listing.pt')\ndef listing(_):\n    videos = video_service.all_videos()\n    model = dict(videos=videos)\n    return chameleon_partials.extend_model(model)\n```\n\nAgain: If you are using Pyramid, use the middleware. Otherwise, use the `extend_model()` method or something \nsimilar to them middleware in your framework.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeckennedy%2Fchameleon_partials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikeckennedy%2Fchameleon_partials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikeckennedy%2Fchameleon_partials/lists"}