1010.. image :: https://codecov.io/gh/fabiommendes/hyperpython/branch/master/graph/badge.svg
1111 :target: https://codecov.io/gh/fabiommendes/hyperpython
1212 :alt: Code coverage
13+ .. module :: hyperpython
1314
1415
15- HyperPython
16+ Hyperpython
1617===========
1718
18- HyperPython is a Python interpretion of
19- `Hyperscript <http://https://github.com/hyperhype/hyperscript >`_. If you are not
20- familiar with Hyperscript, think of it as React, but using pure Javascript
21- instead of JSX. Hyperpython allow us to generate, manipulate and query
22- HTML documents using a small DSL embedded in Python. And just like in Hyperscript,
23- the default entry point of Hyperpython the `h ` function:
19+ Hyperpython is a Python interpretation of Hyperscript _. If you are not
20+ familiar with Hyperscript, think of it as a pure Javascript alternative to JSX.
21+ Hyperpython allow us to generate, manipulate and query HTML documents using a
22+ small DSL embedded in Python. Just like Hyperscript, the default entry point is
23+ the :func: `hyperpython.h ` function:
2424
2525>>> from hyperpython import h
26- >>> elem = h(' p' , {' class' : ' hello' }, ' Hello World!' )
26+ >>> elem = h(' p' , {' class' : ' hello' }, [' Hello World!' ])
27+
28+ .. _Hyperscript : https://github.com/hyperhype/hyperscript
2729
2830This can be converted to HTML by calling ``str() `` on the element:
2931
3032>>> print (elem)
3133<p class="hello">Hello World!</p>
3234
33- The p tag can also be created by the standalone p function (and we have a
34- corresponding function to each valid HTML5 tag).
35+ It accepts Hyperscript's ``h(tag, attributes, list_of_children) `` signature,
36+ but we encourage to use more idiomatic Python version that uses keyword arguments to
37+ represent attributes instead of a dictionary. If the list of children contains a
38+ single element, we can also omit the brackets:
39+
40+ >>> h(' p' , ' Hello World!' , class_ = ' hello' ) == elem
41+ True
42+
43+ Notice in the snippet above that we had to escape the "class" attribute because
44+ it is a reserved word in Python. Hyperpython maps Python keyword arguments by replacing
45+ underscores with dashes and by escaping Python reserved words such as "class", "for"
46+ "from", etc with a trailing underscore.
3547
36- >>> print (p({' class' : ' hello' }, ' Hello World!' ))
48+ Elements can be be more conveniently created with standalone functions representing
49+ specific tags:
50+
51+ >>> print (p(' Hello World!' , class_ = ' hello' ))
3752<p class="hello">Hello World!</p>
3853
39- There is also no problem with nested structures:
54+ In Python, keyword arguments cannot appear after positional arguments. This means
55+ that attributes are placed *after * the list of children, which isn't natural to
56+ represent HTML. For simple elements like the ones above, it does not hinders
57+ legibility, but for larger structures it can be a real issue. Hyperpython
58+ provides two alternatives. The first uses the index notation:
59+
4060
4161>>> from hyperpython import div, p, h1
4262>>> fragment = \
@@ -45,10 +65,24 @@ There is also no problem with nested structures:
4565... p(' Now you can write HTML in Python!' ),
4666... ]
4767
48- HyperPython returns a DOM-like structure which we can introspect, query and
49- modify later. The main usage, of course, is to generate strings of HTML source
50- code. We can apply the str() function for a compact representation of the output
51- code or call ``.pretty() `` method to to get a more human-friendly output.
68+ The second alternative is to use the "children" pseudo-attribute. This is the
69+ approach taken by some Javascript libraries such as React:
70+
71+ >>> fragment = \
72+ ... div(class_ = " alert-box" ,
73+ ... children = [
74+ ... h1(' Hello Python' ),
75+ ... p(' Now you can write HTML in Python!' ),
76+ ... ])
77+
78+
79+ Hyperpython returns a DOM-like structure which we can introspect, query and
80+ modify later. The main usage, of course, is to render strings of HTML source
81+ code. We expect that the main use of Hyperpython will be to complement (or even replace)
82+ the templating language in a Python web application. That said, Hyperpython generates a
83+ very compact HTML that is efficient to generate and transmit over the wire. To
84+ get a more human-friendly output (and keep your sanity while debugging), use
85+ the .pretty() method:
5286
5387>>> print (fragment.pretty())
5488<div class="alert-box">
@@ -58,41 +92,40 @@ code or call ``.pretty()`` method to to get a more human-friendly output.
5892<BLANKLINE>
5993
6094
61- Secret goal: replace templating
62- ===============================
95+ Replacing templates
96+ ===================
6397
6498The goal of ``hyperpython `` is to replace a lot of work that would be traditionally
6599done with a template engine such as Jinja2 by Python code that generates HTML
66- fragments. Templating languages are obviously more efficient than pure Python for
67- string interpolation, and should work fine for simple documents. For large systems,
68- however, templating can be tedious to create and very hard to maintain.
69- Templating is usually not a good answer to handle growing complexity.
70-
71- Many recent Javascript libraries had played with direct manipulation of DOM or
72- virtual DOM nodes sidestepping the whole business of creating intermediate
73- HTML strings. React was probably the library that popularized this idea. As they
100+ fragments. Templating languages are obviously more expressive than pure Python for
101+ string interpolation, and are a perfect match for ad hoc documents. For large systems,
102+ they offer little in terms of architecture, organization and code reuse.
103+
104+ A recent trend in Javascript is to promote direct creation of DOM or
105+ virtual DOM nodes sidestepping the whole business of rendering intermediate
106+ HTML strings. React was probably the library that better popularized this idea. As they
74107nicely put, "Templates separate technologies, not concerns". There is no point
75- on choosing a deliberately underpowered templating language that has poorly
76- communicates with your data sources and outputs your document in a flat string
77- representation since it does not improve architecture or organization .
108+ on choosing a deliberately underpowered programming language that integrates
109+ poorly with your data sources just to output structured documents in a flat string
110+ representation.
78111
79112The same lesson can be applied to Python on the server side. With Hyperpython,
80- we generate HTML directly in Python, instead of passing through an intermediate
81- templating step.
113+ we can generate HTML directly in Python. Hyperpython plays nicely with
114+ existing templating systems, but it makes easy to migrate parts of your rendering
115+ sub-system to Python.
82116
83117For those afraid of putting too much logic on templates, we recognize that
84118Hyperpython doesn't prevent anyone from shooting themselves on the foot, but neither
85- do any minimally powerful templating language. The discipline we must exercise
86- is to keep business logic separated from view logic (i.e., separate concerns).
87- Our advice is to break your code in small pieces and compose those pieces in
88- simple and predictable ways. Incidentally, this is a good advice for any piece
89- of code ;).
119+ do any minimally powerful templating engine. It always requires some discipline to
120+ keep business logic separated from view logic. Our advice is to break code in
121+ small pieces and compose those pieces in simple and predictable ways.
122+ Incidentally, this is a good advice for any piece of code ;).
90123
91124
92125Can it be used on Django? Flask? Etc?
93126=====================================
94127
95- Yes ! Hyperpython is completely framework agnostic. We have a few optional
128+ Of course ! Hyperpython is completely framework agnostic. We have a few optional
96129integrations with Django, but it does not prevent Hyperpython of being used
97130in other frameworks or without any framework at all. It implements the __html__
98131interface which is recognized by most templating engines in Python. That way, it
0 commit comments