html

with domonic you can create beautiful, clean <html> straight out of the box.

mydom = html(body(h1('Hello, World!')))
print(f"{mydom}")
<!DOCTYPE html>
<html>
    <body>
        <h1>Hello, World!</h1>
    </body>
</html>

rendering

you can cast str() on any element to render it.

el_string = str(div())
print(el_string)

there’s also a render method that takes 2 parameters, some pyml and an optional output file.

from domonic.html import *
    page = div(span('Hello World'))
    render(page, 'index.html')

templating

from domonic.html import *

  output = render(
      html(
          head(
              style(),
              script(),
          ),
          body(
              div("hello world"),
              a("this is a link", _href="http://www.somesite.com", _style="font-size:10px;"),
              ol(''.join([f'{li()}' for thing in range(5)])),
              h1("test", _class="test"),
          )
      )
  )
<html><head><style></style><script></script></head><body><div>hello world</div><a href="http://www.somesite.com" style="font-size:10px;">this is a link</a><ol><li></li><li></li><li></li><li></li><li></li></ol><h1 class="test">test</h1></body></html>

Take a look in tests/test_html.py at the bootstrap5 alpha examples. All tests passed on several templates.

usage

print(html(body(h1('Hello, World!'))))
<html><body><h1>Hello, World!</h1></body></html>

attributes

prepend attributes with an underscore ( avoids clashing with python keywords )

test = label(_class='classname', _for="someinput")
print(test)
<label class="classname" for="someinput"></label>

lists

just do list comprehension and join it to strip the square brackets

ul(''.join([f'{li()}' for thing in range(5)])),
<ul><li></li><li></li><li></li><li></li></ul>

data-tags

python doesn’t allow hyphens in parameter names. so use variable keyword argument syntax for custom data-tags

div("test", **{"_data-test":"test"} )

DONT FORGET TO PREPEND THE UNDERSCORE.

script tags

load from a source…

script(_src="/docs/5.0/dist/js/bootstrap.bundle.min.js", _integrity="sha384-1234", _crossorigin="anonymous"),

or do inline js…

    script("""
let itbe = ""
"""),

style tags

load from a source…

link(_href="/docs/5.0/dist/css/bootstrap.min.css", _rel="stylesheet", __integrity="sha384-12345", __crossorigin="anonymous"),

or do inline css…

style("""
.bd-placeholder-img {
    font-size: 1.125rem;
    text-anchor: middle;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
    font-size: 3.5rem;
}
}
"""),

Create Elements

to create your own custom elements you can use create_element

from domonic.html import *
create_element('custom_el', div('some content'), _id="test")

or you could use the DOM API…

from domonic.dom import *
from domonic.html import *

site = html()
el = document.createElement('myelement')
site.appendChild(el)
print(site)

For more info about the DOM API navigate to that section…

Decorators

You can use decorators to wrap elements around function results

from domonic.decorators import el

@el(html)
@el(body)
@el(div)
def test():
        return 'hi!'

print(test())
# <html><body><div>hi!</div></body></html>

Magic methods

Multiply

You can quickly clone nodes with a multiplier which will return a list…

from domonic.html import *
mydivs = div()*100

but you will have to render them yourself by interating and calling string…

print(''.join([str(c) for c in mydivs]))

Divide

A divisor also creates more but will instead call render and give a list of strings…

from domonic.html import *
print(div()/100)

but this means they are now rendered and can’t be edited.

Although you could convert them back by calling parser then domonify. i.e.

mylist = li()/10
myobj = domonic.domonify(domonic.parse(mylist))
print(myobj)

OR

If other is anything, it is returned. Otherwise it returns self

from domonic.html import *
print(div() | False)
print(div() | True)

Another way is to use ternary i.e.

mything = div() if True else span(class-'warning')

In place add/minus

You can add to or remove from the children of a Node with the in-place operators…

myorderedlist = ol()
myorderedlist += str(li() / 10)
print(myorderedlist)

This also works for text nodes but be aware they will be irreversibly flattened if you render…

a1 = button()
a1 += "hi"
a1 += "how"
a1 += ["are", "you", "today"]
print(a1)
a1 -= "hi"
print(a1)

Pass a dictionary to the right shift operator to add/update an attribute… (don’t forget underscore or it will error)

a1 = img()
a1 >> {'_src': "http://www.someurl.com"}
print(a1)

Access an elements children as if it were a list…

mylist = ul(li(1), li(2), li(3))
print(mylist[1])

unpack children…

mylist = ul(li(), li(), li())
print(*mylist)
a1, b1, c1 = ul(li(1), li(2), li(3))
print(a1)
a1, b1, c1, d1, e1 = button() * 5
print(a1, b1, c1, d1, e1)

f-strings

To pretty print a domonic dom you can use a f-string…

print(f"{mydom}")
<!DOCTYPE html>
<html>
    <body>
        <h1>Hello, World!</h1>
    </body>
</html>

which basically calls the format dunder on the tag. (if look at the code)

This is useful as it means use different ways to get output from domonic.

print(f"{mydom}")

print(f"{mydom!s}")

print(f"{mydom!r}")

print(f"{mydom!a}")

print(str(mydom))

print(mydom.__format__(''))

If the built in formatter is not up to your needs. You can also use other libraries that leverage beautifulsoup i.e.

output = render(html(body(h1('Hello, World!'))))
from html5print import HTMLBeautifier
print(HTMLBeautifier.beautify(output, 4))

For outputting pyml to a string there is a method in production called __pyml__() which may become repr. (but i’d been saving repr for logging)

You can also use this vscode plugin on .pyml and it does a nice job. (inpsiration for the ‘dentage’ method)

https://marketplace.visualstudio.com/items?itemName=mgesbert.indent-nested-dictionary

Quotes around attributes

The quotes around attributes can be finely controlled using the DOMConfig.ATTRIBUTE_QUOTES flag

By default everything is double quoted on render.

However a flag can be set to None which will not render quotes if the passed value is not a string.

Alternatively it can be set to use a single quotation mark or even False to use None at all and control it yourself.

Examples provided below.

>>> from domonic.html import *
>>> from domonic.dom import DOMConfig
>>> print(body(test="123"))
# <body test="123"></body>
>>> print(body(test=123))
# <body test="123"></body>
>>> DOMConfig.ATTRIBUTE_QUOTES = None
>>> print(body(test=123))
# <body test=123></body>
>>> print(body(test="123"))
# <body test="123"></body>
>>> DOMConfig.ATTRIBUTE_QUOTES = "'"
>>> print(body(test="123"))
# <body test='123'></body>
>>> DOMConfig.ATTRIBUTE_QUOTES = True
>>> print(body(test="123"))
# <body test="123"></body>
>>> print(body(test=123))
# <body test="123"></body>
>>> DOMConfig.ATTRIBUTE_QUOTES = False
>>> print(body(test="123"))
# <body test=123></body>
>>> print(body(test="TEXT"))
# <body test=TEXT></body>

loading .pyml templates

div("Hello World")
#<div>Hello tabs</div>

‘loads’ imports a pyml file and turns it into a program

this example loads a template and passing params for rendering

from domonic import loads
from domonic.html import *

# create some vars. you will see these referenced in the template file
brand = "MyBrand"
links = ['one', 'two', 'three']

# load a template and pass it some data
webpage = domonic.loads('templates/webpage.com.pyml', links=links, brand=brand)

render(webpage, 'webpage.html')

# ‘load’ is different to ‘loads’, it takes html strings and converts to a program

from domonic.dQuery import º

webpage = domonic.load('<html><head></head><body id="test"></body></html>')
º(webpage)
º('#test').append(div("Hello World"))
render(webpage, 'webpage2.html')
  • warning loads also is very basic and can only convert simple html as the parser is still in development

Notes on templating

while you can create a div with content like :

div("some content")

python doesn’t allow named params before unamed ones. So you can’t do this:

div(_class="container", p("Some content") )

or it will complain the params are in the wrong order. You have to instead put content before attributes:

div( p("Some content"), _class="container")

which is annoying when a div gets long.

You can get around this by using ‘html’ which is available on every Element:

div( _class="container" ).html("Some content")

This is NOT like jQuery html func that returns just the inner content. use innerHTML for that.

It is used specifically for rendering.

Common Errors

If a templates syntax is incorrect it will not work.

There’s a small learning curve in getting .pyml templates correct. Usually…

    1. a missing comma between tags,

    1. an underscore missing on an attribute or

    1. params in the wrong order.

Use this reference when starting out to help when you get an error.

IndexError: list index out of range
# You most likely didn't put a underscore on an attribute.

SyntaxError: invalid syntax
# You are Missing a comma between attributes

SyntaxError: positional argument follows keyword argument
# You have to pass attributes LAST. and strings and objects first. *see notes on templating above*

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'dict'
# You are Missing a comma between attributes. before the **{}

parsing

https://github.com/byteface/domonic/issues/28

Basic useage…

An examples of using the parser…

import requests
import html5lib
from domonic.ext.html5lib_ import getTreeBuilder


r = requests.get("https://google.com")
parser = html5lib.HTMLParser(tree=getTreeBuilder())
page = parser.parse(r.content.decode("utf-8"))

# print the page with formatting
# print(f'{page}')

'''
links = page.getElementsByTagName('a')
for l in links:
    try:
        print(l.href)
    except Exception as e:
        # no href on this tag
        pass
'''

# turn the downloaded site into .pyml ;)
print(page.__pyml__())

For a quick parse try the window module…

from domonic.window import *
window.location = "http://www.google.com"
print(window.document.title)

domonic.html

Generate HTML using python.

exception domonic.html.TemplateError(error, message='TemplateError: ')[source]
class domonic.html.a(*args, **kwargs)
class domonic.html.abbr(*args, **kwargs)
class domonic.html.address(*args, **kwargs)
class domonic.html.applet(*args, **kwargs)
class domonic.html.area(*args, **kwargs)
class domonic.html.article(*args, **kwargs)
class domonic.html.aside(*args, **kwargs)
class domonic.html.audio(*args, autoplay: Optional[bool] = None, controls=None, loop=None, muted=None, preload=None, src=None, **kwargs)
class domonic.html.b(*args, **kwargs)
class domonic.html.base(*args, href=None, target=None, **kwargs)
class domonic.html.basefont(*args, **kwargs)
class domonic.html.bdi(*args, **kwargs)
class domonic.html.bdo(*args, **kwargs)
class domonic.html.blockquote(*args, **kwargs)
class domonic.html.body(*args, aLink=None, background=None, bgColor=None, link=None, onload=None, onunload=None, text=None, vLink=None, **kwargs)
class domonic.html.br(*args, **kwargs)
class domonic.html.button(*args, disabled: Optional[bool] = None, form=None, formaction: Optional[str] = None, formenctype=None, formmethod=None, formnovalidate=None, formtarget=None, name=None, type=None, value=None, **kwargs)
class domonic.html.canvas(*args, width: Optional[int] = None, height: Optional[int] = None, **kwargs)
class domonic.html.caption(*args, **kwargs)
class domonic.html.center(*args, **kwargs)
class domonic.html.cite(*args, **kwargs)
class domonic.html.closed_tag(*args, **kwargs)[source]
class domonic.html.code(*args, **kwargs)
class domonic.html.col(*args, **kwargs)
class domonic.html.colgroup(*args, **kwargs)
class domonic.html.command(*args, **kwargs)
class domonic.html.comment(data)
domonic.html.create_element(name='custom_tag', *args, **kwargs)[source]

A method for creating custom tags

tag name needs to be set due to custom tags with hyphens can’t be classnames. i.e. hypenated tags <some-custom-tag></some-custom-tag>

class domonic.html.data(*args, **kwargs)
class domonic.html.datalist(*args, **kwargs)
class domonic.html.dd(*args, **kwargs)
class domonic.html.details(*args, **kwargs)
class domonic.html.dfn(*args, **kwargs)
class domonic.html.dialog(*args, open=None, **kwargs)
class domonic.html.div(*args, **kwargs)
class domonic.html.dl(*args, **kwargs)
class domonic.html.doctype(name: str = 'html', publicId: str = '', systemId: str = '')
class domonic.html.dt(*args, **kwargs)
class domonic.html.em(*args, **kwargs)
class domonic.html.embed(*args, **kwargs)
class domonic.html.fieldset(*args, **kwargs)
class domonic.html.figcaption(*args, **kwargs)
class domonic.html.figure(*args, **kwargs)
class domonic.html.font(*args, **kwargs)
class domonic.html.footer(*args, **kwargs)
class domonic.html.form(*args, **kwargs)[source]
class domonic.html.h1(*args, **kwargs)
class domonic.html.h2(*args, **kwargs)
class domonic.html.h3(*args, **kwargs)
class domonic.html.h4(*args, **kwargs)
class domonic.html.h5(*args, **kwargs)
class domonic.html.h6(*args, **kwargs)
class domonic.html.head(*args, **kwargs)
class domonic.html.header(*args, **kwargs)
class domonic.html.hgroup(*args, **kwargs)
class domonic.html.hr(*args, **kwargs)
class domonic.html.html(*args, **kwargs)
class domonic.html.i(*args, **kwargs)
class domonic.html.iframe(*args, **kwargs)
class domonic.html.img(*args, alt=None, src=None, crossorigin=None, height=None, ismap=None, longdesc=None, sizes=None, srcset=None, usemap=None, width=None, **kwargs)
class domonic.html.input(*args, accept=None, alt=None, autocomplete=None, autofocus=None, checked=None, dirname=None, disabled=None, form=None, formaction=None, formenctype=None, formmethod=None, formnovalidate=None, formtarget=None, height=None, _list=None, _max=None, maxlength=None, _min=None, multiple=None, name=None, pattern=None, placeholder=None, readonly=None, required=None, size=None, src=None, step=None, type=None, value=None, width=None, **kwargs)
class domonic.html.ins(*args, **kwargs)
class domonic.html.isindex(*args, **kwargs)
class domonic.html.kbd(*args, **kwargs)
class domonic.html.keygen(*args, **kwargs)
class domonic.html.label(*args, **kwargs)
class domonic.html.legend(*args, **kwargs)
class domonic.html.li(*args, **kwargs)
class domonic.html.link(*args, **kwargs)
class domonic.html.listing(*args, **kwargs)
class domonic.html.main(*args, **kwargs)
class domonic.html.mark(*args, **kwargs)
class domonic.html.menu(*args, **kwargs)
class domonic.html.menuitem(*args, **kwargs)
class domonic.html.meta(*args, charset=None, content=None, http_equiv=None, name=None, **kwargs)
class domonic.html.meter(*args, value=None, _min=None, _max=None, low=None, high=None, optimum=None, **kwargs)
class domonic.html.nav(*args, **kwargs)
class domonic.html.noscript(*args, **kwargs)
class domonic.html.ol(*args, **kwargs)
class domonic.html.optgroup(*args, **kwargs)
class domonic.html.option(*args, disabled=None, label=None, selected=None, value=None, **kwargs)
class domonic.html.output(*args, **kwargs)
class domonic.html.p(*args, **kwargs)
class domonic.html.param(*args, **kwargs)
class domonic.html.picture(*args, **kwargs)
class domonic.html.plaintext(*args, **kwargs)
class domonic.html.portal(*args, **kwargs)
class domonic.html.pre(*args, **kwargs)
class domonic.html.progress(*args, **kwargs)
class domonic.html.q(*args, **kwargs)
domonic.html.render(inp, outp='', to=None)[source]

write the input to string or to a file.

Parameters
  • inp (obj) – A domonic tag. For example div()

  • outp (str) – An optional output filename

  • to (str) – An optional output type. if ‘pyml’ is specified then pyml is returned instead of html.

Returns

A HTML rendered string

Return type

str

class domonic.html.rp(*args, **kwargs)
class domonic.html.rt(*args, **kwargs)
class domonic.html.ruby(*args, **kwargs)
class domonic.html.s(*args, **kwargs)
class domonic.html.samp(*args, **kwargs)
class domonic.html.script(*args, **kwargs)
class domonic.html.section(*args, **kwargs)
class domonic.html.select(*args, autofocus: Optional[bool] = None, disabled: Optional[bool] = None, multiple: Optional[bool] = None, name: Optional[str] = None, required: Optional[bool] = None, size: Optional[int] = None, **kwargs)
class domonic.html.small(*args, **kwargs)
class domonic.html.source(*args, **kwargs)
class domonic.html.span(*args, **kwargs)
class domonic.html.strike(*args, **kwargs)
class domonic.html.strong(*args, **kwargs)
class domonic.html.style(*args, **kwargs)
class domonic.html.sub(*args, **kwargs)
class domonic.html.submit(*args, **kwargs)
class domonic.html.summary(*args, **kwargs)
class domonic.html.sup(*args, **kwargs)
class domonic.html.table(*args, align: Optional[str] = None, bgcolor=None, border=None, cellpadding=None, cellspacing=None, frame=None, rules=None, summary=None, width=None, **kwargs)
class domonic.html.tbody(*args, **kwargs)
class domonic.html.td(*args, **kwargs)
class domonic.html.template(*args, **kwargs)
class domonic.html.textarea(*args, autofocus=None, cols=None, disabled=None, form=None, maxlength=None, name=None, placeholder=None, readonly=None, required=None, rows=None, wrap=None, **kwargs)
class domonic.html.tfoot(*args, **kwargs)
class domonic.html.th(*args, **kwargs)
class domonic.html.thead(*args, **kwargs)
class domonic.html.title(*args, **kwargs)
class domonic.html.tr(*args, **kwargs)
class domonic.html.track(*args, **kwargs)
class domonic.html.u(*args, **kwargs)
class domonic.html.ul(*args, **kwargs)
class domonic.html.var(*args, **kwargs)
class domonic.html.video(*args, autoplay=None, controls=None, height=None, loop=None, muted=None, poster=None, preload=None, src=None, width=None, **kwargs)
class domonic.html.wbr(*args, **kwargs)
class domonic.html.xmp(*args, **kwargs)