Basic Markup eXpressions
Project description
BMX - Basic Markup eXpressions
A DSL for representing HTML/XML in Python using an expression-like syntax. Why? You get to use the Python syntax you already know.
Example
Taking the example from the Jinja2 website: | This can be represented in BMX like this: |
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="navigation">
{% for item in navigation %}
<li>
<a href="{{ item.href }}">{{ item.caption }}</a>
</li>
{% endfor %}
</ul>
<h1>My Webpage</h1>
{{ a_variable }}
{# a comment #}
</body>
</html>
|
mydoc = (
DOCTYPE('html')
+html(lang='en')
+head
+title +"My Webpage" -title
-head
+body
+ul('#navigation') +(
+li
+a(href=item.href) +item.caption -a
-li
for item in navigation)
-ul
+h1 +"My Webpage" -h1
+a_variable
# a comment
-body
-html)
|
Note: Just as with ordinary Python expressions, multi-line BMX expressions must be surrounded by parentheses.
How does it work?
We define a Tag
class which overrides the unary +/- and binary +/- operators to model the opening and closing tags of HTML. We provide a __call__
method to model HTML attributes as keyword arguments and a __getattr__
method to provide a shorthand for HTML classes (see below). A Tag
is instantiated for every HTML tag and is available with a from bmx.htmltags import html, head, body, span
.
Usage
An example using Flask (available in the top-level source directory):
# flask_greeter.py
from bmx.htmltags import (
html,
head,
title,
body,
p
)
from flask import Flask
app = Flask(__name__)
@app.route('/<name>')
def greeter(name: str):
return str(
# fmt: off
+html
+head
+title +"Flask Greeter" -title
-head
+body
+p +f"Hello {name}" -p
-body
-html
# fmt: on
)
Install Flask then run it as:
FLASK_APP=flask_greeter.py flask run
Go to https://127.0.0.1:5000/<your_name>
in your browser (eg. https://127.0.0.1:5000/Stuart
) and you will see the message.
Table of Conversions
Type | HTML | BMX | Comment/Mnemonic |
---|---|---|---|
Opening tag | <div> |
+div |
Mnemonic: Adding content |
Closing tag | </div> |
-div |
Mnemonic: opposite of adding content |
Self-closing tag | <input/> |
+input |
Self-closing tag are pre-defined |
Attributes | <input type="text"> |
+input_(type_="text") |
Mnemonic: attributes are keyword arguments. Note: Append an underscore to avoid conflicts with Python keywords |
Attributes: shorthand for id and class |
<div id="userinput" class="credentials" > |
+div('#userinput.credentials') |
#id .classname |
Attributes: shorthand for class |
<div class="col-sm-8 col-md-7 py-4"> |
+div .col_sm_8 .col_md_7 .py_4 |
.classname Underscores are transposed to dashes |
Composing tags and content | <h1>The Title</h1> |
+h1 +"The Title" -h1 |
Mnemonic: think string concatenation ie. "Hello " + "World!" |
Autoformatters
Black
To use the Black uncompromising autoformatter, surround your BMX markup with #fmt: off
and #fmt: on
comments like this:
result = (
# fmt: off
+html
+body
+h1 +"My Page" -h1
-body
-html
# fmt: on
)
Autopep8
To use autopep8, you can use the #fmt: off
and #fmt: on
comments as above or turn off 2 fixes:
- E225 - Fix missing whitespace around operator.
- E131 - Fix hanging indent for unaligned continuation line.
whereever you put your autopep8 configuration
ignore = E225,E131
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.