Package: airium
AiriumBidirectionalHTML-pythontranslator.Key features:simple, straight-forwardtemplate-less (just the python, you may say goodbye to all the templates)DOM structure is strictly represented by python indentation (with context-managers)gives much cleanerHTMLthan regular templatesequipped with reverse translator:HTMLto pythoncan output either pretty (default) or minifiedHTMLcodeGeneratingHTMLcode in python usingairiumBasicHTMLpage (hello world)fromairiumimportAiriuma=Airium()a('<!DOCTYPE html>')witha.html(lang="pl"):witha.head():a.meta(charset="utf-8")a.title(_t="Airium example")witha.body():witha.h3(id="id23409231",klass='main_header'):a("Hello World.")html=str(a)# casting to string extracts the value# or directly to UTF-8 encoded bytes:html_bytes=bytes(a)# casting to bytes is a shortcut to str(a).encode('utf-8')print(html)Prints such a string:<!DOCTYPE html><htmllang="pl"><head><metacharset="utf-8"/><title>Airium example</title></head><body><h3id="id23409231"class="main_header">Hello World.</h3></body></html>In order to store it as a file, just:withopen('that/file/path.html','wb')asf:f.write(bytes(html))Simple image in a divfromairiumimportAiriuma=Airium()witha.div():a.img(src='source.png',alt='alt text')a('the text')html_str=str(a)print(html_str)<div><imgsrc="source.png"alt="alt text"/>the text</div>TablefromairiumimportAiriuma=Airium()witha.table(id='table_372'):witha.tr(klass='header_row'):a.th(_t='no.')a.th(_t='Firstname')a.th(_t='Lastname')witha.tr():a.td(_t='1.')a.td(id='jbl',_t='Jill')a.td(_t='Smith')# can use _t or textwitha.tr():a.td(_t='2.')a.td(_t='Roland',id='rmd')a.td(_t='Mendel')table_str=str(a)print(table_str)# To store it to a file:withopen('/tmp/airium_www.example.com.py')asf:f.write(table_str)Nowtable_strcontains such a string:<tableid="table_372"><trclass="header_row"><th>no.</th><th>Firstname</th><th>Lastname</th></tr><tr><td>1.</td><tdid="jbl">Jill</td><td>Smith</td></tr><tr><td>2.</td><tdid="rmd">Roland</td><td>Mendel</td></tr></table>Chaining shortcut for elements with only one childNew in version 0.2.2Having a structure with large number ofwithstatements:fromairiumimportAiriuma=Airium()witha.article():witha.table():witha.thead():witha.tr():a.th(_t='Column 1')a.th(_t='Column 2')witha.tbody():witha.tr():witha.td():a.strong(_t='Value 1')a.td(_t='Value 2')table_str=str(a)print(table_str)You may use a shortcut that is equivalent to:fromairiumimportAiriuma=Airium()witha.article().table():witha.thead().tr():a.th(_t="Column 1")a.th(_t="Column 2")witha.tbody().tr():a.td().strong(_t="Value 1")a.td(_t="Value 2")table_str=str(a)print(table_str)<article><table><thead><tr><th>Column 1</th><th>Column 2</th></tr></thead><tbody><tr><td><strong>Value 1</strong></td><td>Value 2</td></tr></tbody></table></article>OptionsPretty or MinifyBy default, airium biuldsHTMLcode indented with spaces and with line breaks being line feed\ncharacters.
It can be changed while creating anAiriuminstance. In general all avaliable arguments whit their default values are:a=Airium(base_indent='  ',# strcurrent_level=0,# intsource_minify=False,# boolsource_line_break_character="\n",# str)minifyThat's a mode when size of the code is minimized, i.e. contains as less whitespaces as it's possible.
The option can be enabled withsource_minifyargument, i.e.:a=Airium(source_minify=True)In case if you need to explicitly add a line break in the source code (not the<br/>):a=Airium(source_minify=True)a.h1(_t="Here's your table")witha.table():witha.tr():a.break_source_line()a.th(_t="Cell 11")a.th(_t="Cell 12")witha.tr():a.break_source_line()a.th(_t="Cell 21")a.th(_t="Cell 22")a.break_source_line()a.p(_t="Another content goes here")Will result with such a code:<h1>Here's your table</h1><table><tr><th>Cell 11</th><th>Cell 12</th></tr><tr><th>Cell 21</th><th>Cell 22</th></tr></table><p>Another content goes here</p>Note that thebreak_source_linecannot be used
incontext manager chains.indent styleThe default indent of the generated HTML code has two spaces per each indent level.
You can change it to\tor 4 spaces by settingAiriumconstructor argument, e.g.:a=Airium(base_indent="\t")# one tab symbola=Airium(base_indent="    ")# 4 spaces per each indentation levela=Airium(base_indent=" ")# 1 space per one level# pick one of the above statements, it can be mixed with other argumentsNote that this setting is ignored whensource_minifyargument is set toTrue(see above).There is a special case when you set the base indent to empty string. It would disable indentation,
but line breaks will be still added. In order to get rid of line breaks, check thesource_minifyargument.indent levelThecurrent_levelbeing an integer can be set to non-negative
value, wich will causeairiumto start indentation with level offset given by the number.line break characterBy default, just a line feed (\n) is used for terminating lines of the generated code.
You can change it to different style, e.g.\r\nor\rby settingsource_line_break_characterto the desired value.a=Airium(source_line_break_character="\r\n")# windows' styleNote that the setting has no effect whensource_minifyargument is set toTrue(see above).Using airium with web-frameworksAirium can be used with frameworks like Flask or Django. It can completely replace
template engines, reducing code-files scater, which may bring better code organization, and some other reasons.Here is an example of using airium with django. It implements reusablebasic_bodyand a view calledindex.# file: your_app/views.pyimportcontextlibimportinspectfromairiumimportAiriumfromdjango.httpimportHttpResponse@contextlib.contextmanagerdefbasic_body(a:Airium,useful_name:str=''):"""Works like a Django/Ninja template."""a('<!DOCTYPE html>')witha.html(lang='en'):witha.head():a.meta(charset='utf-8')a.meta(content='width=device-width, initial-scale=1',name='viewport')# do not use CSS from this URL in a production, it's just for an educational purposea.link(href='https://unpkg.com/@picocss/pico@1.4.1/css/pico.css',rel='stylesheet')a.title(_t=f'Hello World')witha.body():witha.div():witha.nav(klass='container-fluid'):witha.ul():witha.li():witha.a(klass='contrast',href='./'):a.strong(_t="⌨ Foo Bar")witha.ul():witha.li():a.a(klass='contrast',href='#',**{'data-theme-switcher':'auto'},_t='Auto')witha.li():a.a(klass='contrast',href='#',**{'data-theme-switcher':'light'},_t='Light')witha.li():a.a(klass='contrast',href='#',**{'data-theme-switcher':'dark'},_t='Dark')witha.header(klass='container'):witha.hgroup():a.h1(_t=f"You're on the{useful_name}")a.h2(_t="It's a page made by our automatons with a power of steam engines.")witha.main(klass='container'):yield# This is the point where main content gets insertedwitha.footer(klass='container'):witha.small():margin='margin: auto 10px;'a.span(_t='© Airium HTML generator example',style=margin)# do not use JS from this URL in a production, it's just for an educational purposea.script(src='https://picocss.com/examples/js/minimal-theme-switcher.js')defindex(request)->HttpResponse:a=Airium()withbasic_body(a,f'main page:{request.path}'):witha.article():a.h3(_t="Hello World from Django running Airium")witha.p().small():a("This bases on ")witha.a(href="https://picocss.com/examples/company/"):a("Pico.css / Company example")witha.p():a("Instead of a HTML template, airium has been used.")a("The whole body is generated by a template ""and the article code looks like that:")witha.code().pre():a(inspect.getsource(index))returnHttpResponse(bytes(a))# from django.http import HttpResponseRoute it inurls.pyjust like a regular view:# file: your_app/urls.pyfromdjango.contribimportadminfromdjango.urlsimportpathimportyour_appurlpatterns=[path('index/',your_app.views.index),path('admin/',admin.site.urls),]The result ing web page on my machine looks like that:Reverse translationAirium is equipped with a transpiler[HTML -> py].
It generates python code out of a givenHTMLstring.Using reverse translator as a binary:Ensure you haveinstalled[parse]extras. Then call in command line:airiumhttp://www.example.comThat will fetch the document and translate it to python code.
The code callsairiumstatements that reproduce theHTMLdocument given.
It may give a clue - how to defineHTMLstructure for a given
web page usingairiumpackage.To store the translation's result into a file:airiumhttp://www.example.com>/tmp/airium_example_com.pyYou can also parse localHTMLfiles:airium/path/to/your_file.html>/tmp/airium_my_file.pyYou may also try to parse your Django templates. I'm not sure if it works,
but there will be probably not much to fix.Using reverse translator as python code:fromairiumimportfrom_html_to_airium# assume we have such a page given as a string:html_str="""\<!DOCTYPE html><html lang="pl"><head><meta charset="utf-8" /><title>Airium example</title></head><body><h3 id="id23409231" class="main_header">Hello World.</h3></body></html>"""# to convert the html into python, just call:py_str=from_html_to_airium(html_str)# airium tests ensure that the result of the conversion is equal to the string:assertpy_str=="""\#!/usr/bin/env python# File generated by reverse AIRIUM translator (version 0.2.6).# Any change will be overridden on next run.# flake8: noqa E501 (line too long)from airium import Airiuma = Airium()a('<!DOCTYPE html>')with a.html(lang='pl'):with a.head():a.meta(charset='utf-8')a.title(_t='Airium example')with a.body():a.h3(klass='main_header', id='id23409231', _t='Hello World.')"""Transpiler limitationsso far in version 0.2.2:result of translation does not keep exact amount of leading whitespaces
within<pre>tags. They come over-indented in python code.This is not however an issue when code is generated from python toHTML.although it keeps the proper tags structure, the transpiler does not
chain all thewithstatements, so in some cases the generated
code may be much indented.it's not too fastInstallationIf you need a new virtual environment, call:virtualenvvenvsourcevenv/bin/activateHaving it activated - you may install airium like this:pipinstallairiumIn order to use reverse translation - two additional packages are needed, run:pipinstallairium[parse]Then check if the transpiler works by calling:airium--helpEnjoy!