Package: nate
natenatemakes generating HTML fun. Rather than forcing you to adopt an entirely different templating language that comes with its own set of quirks, nate is built around a simple, but powerful Python DSL that enables you to easily compose trees of elements that can be translated to well-formed HTML - no more forgotten angle brackets, unbalanced tags, or unescaped user input.Think of nate as an alternative toJinjaorDjango templates.FeaturesMostly typed- The API has been designed with type safety in mind: All
function boundaries have type hints to ensure correctness, ease
documentation, and make auto-completion in the IDE of your choice a piece of
cake.No dependencies- nate does not depend on any third-party libraries.Stable API- The API itself is stable. No breaking changes are planned.Tiny- The core library is approximately 500 eLOC, which is tiny and
can be manually audited on a single afternoon.InstallWithpipinstalled, run$ pip install nateUsageImport the elements you need.fromnateimportTable,Thead,Th,Tr,Tbody,TdConstruct your tree.politicians=[{"first_name":"Theodor","last_name":"Heuss","party":"FDP"},{"first_name":"Heinrich","last_name":"Lübke","party":"CDU"},{"first_name":"Gustav","last_name":"Heinemann","party":"SPD"},# ...]table=Table([Thead(Th([Tr("First Name"),Tr("Last Name"),Tr("Party")])),Tbody(map(lambdapolitician:Tr([Td(politician["first_name"]),Td(politician["last_name"]),Td(politician["party"]),]),politicians,)),])Call.to_html()on your root node to serialize your tree to a string of HTML.table.to_html()#=> <table><thead>....Raw text nodes are escaped by default, thus making it difficult to introduceXSS vulnerabilities.p=P("<script>alert('XSS');</script>")p.to_html()#=> <p>&lt;script&gt;alert(&#x27;XSS&#x27;);&lt;/script&gt;</p>ComponentsTemplating languages tend to come with their own abstractions for building re-usable components. There is no need for those in nate, given that component hierarchies can easily be composed using plain Python functions.fromnateimportDiv,H1,P,BaseTagdefMyComponent(title:str,description:str)->BaseTag:returnDiv(children=[H1(title),P(description),],class_="my-component",)component=MyComponent(title="My title",description="My description",)component.to_html()#=> <div class="my-component>...ExamplesnateHTMLTitle("Hello World!").to_html()<title>Hello World!</title>steaks=["Rib Eye","New York Strip","Porterhouse"]Ul(map(lambdasteak:Li(steak),steaks)).to_html()<ul><li>Rib Eye</li><li>New York Strip</li><li>Porterhouse</li></ul>Html(lang="en",children=[Head(children=[Meta(charset="utf-8"),Title(children="Welcome to nate!"),]),Body(children=[H1("Mission"),P("nate is not a template engine.",class_="red",),],),],).to_html()<!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"/><title>Welcome to nate!</title></head><body><h1>Mission</h1><pclass="red">nate is not a template engine.</p></body></html>How to contributeKeep it simple, don't do anything too crazy. Even folks that don't know Python should be able to understand the code without any issues.Design APIs with type-safety in mind.If your code slows things down, it won't get merged.Avoid introducing new dependencies.If you don't want to follow those rules, forking isencouraged!Ensure new code is covered by corresponding tests.Prior works of artlamernews- While written in Ruby, thepage.rblibrary inspired this project.hyperscript- Pure JavaScript alternative to JSX.hyperpython- Python interpretation of hyperscript.XHPy- Extends Python syntax such that XML document fragments become valid Python expressions. Based off XHP, a similar framework for PHP.LicenseMIT