Skip to content

Commit c838955

Browse files
committed
update documentation
1 parent 5f68ab6 commit c838955

File tree

7 files changed

+129
-100
lines changed

7 files changed

+129
-100
lines changed

INSTALL.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ option and execute as superuser by prepending the command with ``sudo``.
2020
Troubleshoot
2121
------------
2222

23+
Hyperpython requires Python 3.6+. Make sure you use an updated distribution.
24+
2325
Windows users may find that these command will only works if typed from Python's
2426
installation directory.
2527

README.rst

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,30 @@
1313

1414

1515
HyperPython
16-
-----------
16+
===========
1717

1818
HyperPython is a Python interpretion of
1919
`Hyperscript <http://https://github.com/hyperhype/hyperscript>`_. If you are not
20-
familiar with Hyperscript, think of it as being something similar to React to
21-
Python, but without the JSX. This lib allow us to generate, manipulate and query
22-
HTML documents using a small DSL embedded in Python. Just like Hyperscript,
23-
the default entry point is the `h` function:
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:
2424

2525
>>> from hyperpython import h
2626
>>> elem = h('p', {'class': 'hello'}, 'Hello World!')
2727

2828
This can be converted to HTML by calling ``str()`` on the element:
2929

30-
>>> print(str(elem))
30+
>>> print(elem)
3131
<p class="hello">Hello World!</p>
3232

33-
Notice that the p tag could also be imported as a function from the hyperpython
34-
namespace.
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).
3535

36-
Python and HTML have very different semantics. HTML's syntax gravitates
37-
around tag attributes + children nodes and does not have a very natural
38-
counterpart in most programming languages. It is obviously very easy to build
39-
HTML tag in a imperative style, but the end result often feels awkward.
40-
HyperPython embeds a simple DSL mini-language to declare HTML fragments in a
41-
more natural way:
36+
>>> print(p({'class': 'hello'}, 'Hello World!'))
37+
<p class="hello">Hello World!</p>
38+
39+
There is also no problem with nested structures:
4240

4341
>>> from hyperpython import div, p, h1
4442
>>> fragment = \
@@ -47,19 +45,56 @@ more natural way:
4745
... p('Now you can write HTML in Python!'),
4846
... ]
4947

50-
HyperPython stores the DOM node for a later use. We can introspect, query and
51-
modify the result.
52-
53-
>>> fragment.attrs['id'] = 'element-id'
54-
>>> len(fragment.children)
55-
2
56-
57-
str() prints a very compact HTML. Use ``.pretty()`` to get a more human-friendly
58-
version of the HTML.
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.
5952

6053
>>> print(fragment.pretty())
6154
<div class="alert-box" id="element-id">
6255
<h1>Hello Python</h1>
6356
<p>Now you can write HTML in Python!</p>
6457
</div>
65-
<BLANKLINE>
58+
<BLANKLINE>
59+
60+
61+
Secret goal: replace templating
62+
===============================
63+
64+
The goal of ``hyperpython`` is to replace a lot of work that would be traditionally
65+
done 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
74+
nicely 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.
78+
79+
The 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.
82+
83+
For those afraid of putting too much logic on templates, we recognize that
84+
Hyperpython 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 ;).
90+
91+
92+
Can it be used on Django? Flask? Etc?
93+
=====================================
94+
95+
Yes! Hyperpython is completely framework agnostic. We have a few optional
96+
integrations with Django, but it does not prevent Hyperpython of being used
97+
in other frameworks or without any framework at all. It implements the __html__
98+
interface which is recognized by most templating engines in Python. That way, it
99+
is possible to pass Hyperpython fragments to existing templates in Django, Jinja2
100+
and others.

docs/apidoc.rst

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,27 @@ Functions
2424
~~~~~~~~~
2525

2626
The generic entry point is the :func:`h` function. It also has functions with
27-
same names of HTML tags.
27+
same names of all HTML tags.
2828

2929
.. autofunction:: h
3030

3131

32+
Communication with external Python objects
33+
------------------------------------------
3234

33-
Components
34-
----------
35-
36-
Basic interfaces
37-
................
38-
39-
.. automodule:: hyperpython.components
40-
:members: render, render_html
35+
.. module:: hyperpython.components
36+
.. autofunction:: render
37+
.. autofunction:: render_html
4138

4239

4340
Hyperlinks
44-
..........
41+
----------
4542

46-
.. automodule:: hyperpython.components
47-
:members: hyperlink, url, a_or_p, a_or_span, breadcrumbs
43+
.. autofunction:: hyperlink
44+
.. autofunction:: url
45+
.. autofunction:: a_or_p
46+
.. autofunction:: a_or_span
47+
.. autofunction:: breadcrumbs
4848

4949

5050
HTML data structures
@@ -53,8 +53,9 @@ HTML data structures
5353
Those functions convert Python data structures to their natural HTML
5454
representations.
5555

56-
.. automodule:: hyperpython.components
57-
:members: html_list, html_map, html_table
56+
.. autofunction:: html_list
57+
.. autofunction:: html_map
58+
.. autofunction:: html_table
5859

5960

6061
Icons
@@ -63,12 +64,15 @@ Icons
6364
Generic icon support using the <i> tag and helper functions for Font Awesome
6465
icons.
6566

66-
.. automodule:: hyperpython.components
67-
:members: icon, icon_link, fa_icon, fab_icon, fa_link, fab_link
67+
.. autofunction:: icon
68+
.. autofunction:: icon_link
69+
.. autofunction:: fa_icon
70+
.. autofunction:: fab_icon
71+
.. autofunction:: fa_link
72+
.. autofunction:: fab_link
6873

6974

7075
Text
7176
....
7277

73-
.. automodule:: hyperpython.components
74-
:members: markdown
78+
.. autofunction:: markdown

docs/faq.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ Will it ever support Python 3.5 or lower?
1717

1818
Probably not. Hyperpython uses a functional programming library called Sidekick_
1919
which requires Python 3.6+. It is not impossible to port this library to 3.5,
20-
but it is a very low priority for the developers. You can make this happen by
21-
sending pull requests ;)
20+
but it is a very low priority for the developers. Of course, you can make this
21+
happen by sending pull requests ;)
2222

2323

2424
.. _Sidekick: https://github.com/fabiommendes/sidekick/

docs/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ a Python sub-language.
1212

1313
Overview <overview.rst>
1414
Installation instructions <install.rst>
15-
Templating <templating.rst>
16-
Django integration <django.rst>
15+
Tutorial <tutorial.rst>
1716
API documentation <apidoc.rst>
17+
Django integration <django.rst>
1818
Frequently asked questions <faq.rst>
1919
Roadmap <roadmap.rst>
2020
License <license.rst>

docs/templating.rst renamed to docs/tutorial.rst

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,8 @@
11
.. module:: hyperpython
22

3-
==========
4-
Templating
5-
==========
6-
7-
The goal of ``hyperpython`` is to replace a lot of work that would traditionally
8-
be done with a template engine such as Jinja2 by Python code that generates HTML
9-
fragments. Templating languages are obviously more efficient than pure Python for
10-
string interpolation, and should work better for simple cases. For long documents,
11-
however, templating can be very repetitive. HTML is a structured format and we
12-
eliminate duplication by composing simple functions and using other standard
13-
techniques in Software Engineering.
14-
15-
It is becoming increasingly common in the Javascript world to use more
16-
structured approaches to generate HTML code (or direct creation of DOM/virtual DOM nodes).
17-
React was probably the library that popularized this idea. As they elegantly put,
18-
"Templates separate technologies, not concerns". The point being that it is
19-
better to generate DOM nodes in Javascript instead of choosing a deliberately
20-
underpowered language that has a that poorly communicates with your data
21-
sources created in Javascript. The same lesson can be applied to Python on
22-
the server side.
23-
24-
For those afraid of putting too much logic on templates, we recognize that
25-
Hyperpython doesn't prevent anyone from shooting itself on the foot, but neither
26-
does any minimally powerful templating language. The discipline we should exercise
27-
is to keep business logic separate from view logic. Our advice is:
28-
*break your code in small pieces and compose those pieces in simple and predictable ways*.
29-
Incidentally, this is a good advice for any piece of code ;).
30-
31-
Let us dive in!
3+
========
4+
Tutorial
5+
========
326

337
A simple example
348
================
@@ -55,17 +29,17 @@ actions (this is a random example taken from Bootstrap website).
5529
</ul>
5630
</div>
5731

58-
Of course we could translate this directly into Hyperpython code by calling the
59-
corresponding ``div()``'s, ``button()``'s, etc. But first, let us break up this
60-
mess into smaller pieces.
32+
Of course we could translate this directly into Hyperpython by calling the
33+
corresponding ``div()``, ``button()``, etc functions. But first, let us break
34+
up this mess into smaller pieces.
6135

6236
.. code-block:: python
6337
6438
from hyperpython import button, div, p, ul, li, span, a, classes
6539
6640
def menu_button(name, caret=True, class_=None, **kwargs):
6741
if caret:
68-
children = [name, ' ', span(caret)]
42+
children = [name, ' ', span('caret')]
6943
else:
7044
children = [name]
7145
@@ -129,8 +103,8 @@ Look how nice it is now :)
129103
How does it work?
130104
=================
131105

132-
Hyperpython HTML syntax is just regular Python wrapped in a HTML-wannabe DSL.
133-
How does it work?
106+
Hyperpython syntax is just regular Python wrapped in a HTML-wannabe DSL. How
107+
does it work?
134108

135109
Take the example:
136110

@@ -143,8 +117,8 @@ Take the example:
143117
]
144118
145119
In Hyperpython, we can declare attributes as keyword arguments and children as a
146-
index access. This clever abuse of Python syntax is good to creating expressive
147-
representations of HTML documents. Under the hood, Python call div() and
120+
index access. This clever abuse of Python syntax is good for creating expressive
121+
representations of HTML documents. Under the hood, Python calls div() and
148122
generates an :class:`Element` instance. Indexing is used to insert the given
149123
elements as children and then return the tag itself as a result. We encourage
150124
using this syntax only during element creation in order to avoid confusion.
@@ -167,10 +141,9 @@ Tag functions also accept a few alternative signatures:
167141
Children can also be passed as a keyword argument.
168142
This generates ``<h1 class="foo">title</h1>``.
169143

170-
In HTML, tag attributes are all stringly typed. This is far from ideal and can
171-
be easily fixed since we are representing HTML from a more rigorously typed
172-
language. Hyperpython does the following coercions when interpreting
173-
attributes:
144+
In HTML, all tag attributes are all stringly typed. This is far from ideal and can
145+
be easily fixed since we are representing HTML from a typed language.
146+
Hyperpython does the following coercions when interpreting attributes:
174147

175148
"class" attribute:
176149
Hyperpython expects a list of strings. If a single string is given, it is
@@ -190,24 +163,22 @@ Imperative interface
190163
We encourage users to adopt the declarative API and generally treat tags
191164
as immutable structures. Hyperpython does not enforce immutability and actually
192165
offers some APIs to change data structures inplace. Once a tag is created, it
193-
is possible to change it's attributes dictionary and list of children. We
194-
encourage to use the appropriate method instead of manipulating those data
195-
structures directly.
166+
is possible to change it's attributes dictionary and list of children. There
167+
are also a few methods designed to manipulate Hyperpython data structures.
196168

197169
>>> elem = div('foo', class_='elem')
198170
>>> elem.add_child('bar')
199171
>>> print(elem)
200172
<div class="elem">foobar</div>
201173

202-
Similarly to the children property, attributes are also exposed:
174+
Attributes are also exposed in the .attrs dictionary:
203175

204176
>>> elem.attrs['data-answer'] = 42
205177
>>> elem.attrs.keys()
206178
dict_keys(['class', 'data-answer'])
207179

208-
Manipulating the list of classes and the element id also introduces specialized
209-
methods and attributes. The ``.id`` and ``.classes`` attributes expose those
210-
two properties.
180+
The "class" and "id" attributes are also exposed directly from the tag object
181+
since they are used so often:
211182

212183
>>> elem = div('foo', class_='class', id='id')
213184
>>> elem.id, elem.classes

src/hyperpython/tags.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,30 @@
1010

1111
def h(tag, *args, children=None, **attrs):
1212
"""
13-
Create a tag.
13+
Creates a tag.
1414
15-
* ``h('h1', 'content')``
16-
* ``h('h1', {'class': 'title'}, 'content')``
17-
* ``h('h1', 'title', class_='title')``
18-
* ``h('h1', class_='title')['content']``
19-
* ``h('h1', class_='title', children=['content'])``
15+
It has many different signatures:
16+
17+
h('h1', 'content')
18+
Content can be a string, a child node or a list of children.
19+
20+
h('h1', {'class': 'title'}, 'content')
21+
If the second argument is a dictionary, it is interpreted as tag
22+
attributes.
23+
24+
h('h1', 'title', class_='title')
25+
Keyword arguments are also interpreted a attributes. The h function
26+
makes a few changes: underscores are converted to dashes and trailing
27+
underscores after Python keywords such as ``class_``, ``for_``, etc are
28+
ignored.
29+
30+
h('h1', class_='title')['content']
31+
Children can also be specified using squared brackets. It understands
32+
strings, other tags, and lists of tags.
33+
34+
h('h1', class_='title', children=['content'])
35+
Optionally, the list of children nodes can be specified as a keyword
36+
argument.
2037
"""
2138
attr_name = html_safe_natural_attr
2239
is_void = tag in VOID_ELEMENTS

0 commit comments

Comments
 (0)