--- title: 5.2 Web Apps - PyHTML (document) tags: COMP1010-22T1 slideOptions: transition: slide --- <style> .reveal { font-size: 30px; } .reveal div.para { text-align: left; } .reveal ul { display: block; } .reveal ol { display: block; } img[alt=drawing] { width: 200px; } </style> # 5.2 Web Apps: PyHTML Written by Krishne Thayaparan and Sim Mautner ## Table of Contents 1. [Purpose of this Document](#Purpose-of-this-Document) 2. [Why use PyHTML?](#Why-use-PyHTML?) 3. [Importing PyHTML](#Importing-PyHTML) 4. [Using PyHTML](#Using-PyHTML) 1. [Basic Formatting](#Basic-Formatting) 2. [Tags with Attributes](#Tags-with-Attributes) 3. [Simple Examples](#Simple-Examples) 4. [Forms](#Forms) 1. [Form Components](#Form-Components) 2. [Examples of Forms](#Examples-of-Forms) 5. [Lists, Radio Buttons, Dropdown Menus](#Lists) 6. [Tables](#Tables) 7. [Pitfalls](#Pitfalls) 8. [Reference](#Reference) 9. [Feedback](#Feedback) ## Purpose of this Document There is much [documentation on how to write HTML](https://www.w3schools.com/html/default.asp) but very little on how to use PyHTML. This document is designed to help people who know how to write HTML, to write Python code using the PyHTML library to produce HTML web pages. ## Why use PyHTML? * I use PyHTML because: - I find it easier to produce/read. - It is less likely I'll make a mistake in a HTML tag (eg spelling mistake). - It is less likely I'll forget to close a tag, or close it in the wrong place. ## Importing PyHTML Import html library and any html terms you are using (title, body, p, etc). ```{python} from pyhtml import html, title, body, p ``` ## Using PyHTML ### Basic Formatting The w3schools page on HTML still applies. You just need to change your syntax a little to write in PyHTML rather than HTML. The key differences are: * Tags become function names. * Anything that is encompassed between <> and </> becomes encompassed between (). | Description | HTML | PyHTML | Display | |---|---|---|---| |Paragraph|`<p>This is a paragraph.</p>`|`p('This is a paragraph.')`|This is a paragraph.| |Heading 3|`<h3>This is a medium level heading.</h3>`|`h3('This is a medium level heading.)'`|<h3>This is a medium level heading.</h3>| |Bold Text|`<b>This is bold.</b>`|`b('This is bold.')`|**This is bold.**| Remember that there are a lot more possible tags and formats. This document is just to teach you how to convert HTML tags which you already know (or can look up [here (text formatting)](https://www.w3schools.com/html/html_formatting.asp) or [here (whole HTML tag reference)](https://www.w3schools.com/tags/default.asp)) into the equivalent PyHTML. ### Tags with Attributes #### Introduction For elements which have both attributes and children: * HTML is structured: ```{html} <element_name attributes> <children></children> <listed></listed> <like></like> <this></this> </element_name> ``` * PyHTML is structured: ```{python} element_name(attributes)( children(), listed(), like(), this() ) ``` In otherwords, notice how anything inside the <> is put in separate brackets () beforehand. #### Syntax * Link: * HTML: ```{html} <a href="https://www.w3schools.com/">Go to w3schools</a> ``` * PyHTML: ```{python} a(href="https://www.w3schools.com/")("Go to w3schools") ``` * Image: * HTML: ```{html} <img src="https://tinyurl.com/mehrkbd6" width="200px"> ``` * PyHTML: ```{python} img(src="https://tinyurl.com/mehrkbd6", width="200px") ``` ### Simple Examples #### Example * HTML: ```{html} <!DOCTYPE html> <html> <h1>Welcome to COMP1010</h1> </html> ``` * Equivalent PyHTML: ```{python} html( h1('Welcome to COMP1010') ) ``` #### Example * HTML: ```{html} <!DOCTYPE html> <html> <head> <title>Welcome Page</title> </head> <body> <h1>Welcome to COMP1010</h1> <p>This course is about Python and web development.</p> </body> </html> ``` * Equivalent PyHTML: ```{python} html( head( title('Welcome Page') ), body( h1('Welcome to COMP1010'), p('This course is about Python and web development.') ) ) ``` Notice the comma between the `h1` function call and the `p` function call. This is because the `body` function call is taking those two things in as parameters, and they need to be separated by commas. You may list as many things in here as you'd like, as long as they are separated by commas. ### Forms In the sections above, we can display information. Forms allow the user to interact with the browser. For example the user can enter text and click buttons. #### Form Components | Feature | HTML | PyHTML | |---|---|---| |Label|`<label>Name: </label>`|`label('Name:')`| |Text Input|`<input type="text">`|`input_(type="text")`| |Password Input|`<input type="password">`|`input_(type="password")`| |Submit Input|`<input type="submit" value="Text on Button">`|`input_(type="Submit", value='Text on Button')`| You'll notice that the `input` tag in HTML has an underscore (`_`) at the end. This is because there's already a function name `input` in Python (used to take input from the user on the command line). The underscore at the end of the `input_` function call distinguishes when we want to call the PyHTML function rather than the standard Python `input` function. #### Examples of Forms ##### Example Simple Form A form with a single button. * HTML: ```{html} <form> <input type="submit", value="Go"> </form> ``` * Equivalent PyHTML: ```{python} form( input_(type="submit", value="Go") ) ``` ##### Example Simple Form 2 * A form with a single button and a form-handler. * We will learn more about form-handlers when we write our web server. * HTML: ```{html} <form action="my_destination"> <input type="submit", value="Go"> </form> ``` * Equivalent PyHTML: ```{python} form(action="my_destination")( input_(type="submit", value="Go") ) ``` ##### Example More Complex Form A form which asks the user for their name (entered into a textbox) and a button to click when they're done. * HTML: ```{html} <form action="my_destination"> <label>Name: </label> <input type="text"> <input type="submit", value="Go"> </form> ``` * Equivalent PyHTML: ```{python} form(action="my_destination")( label('Name: '), input_(type="text"), input_(type="submit", value="Go") ) ``` ### Lists Lists are more complex than anything we have done so far because when we write the PyHTML, we don't (always) know, when we are writing the app, how long the list will be. First we will look at the different ways to make a list in which we **do** know what the items are when the app is being written. Then we will look at how we can write code which adapts to the user's needs when the app is being run. #### Terminology The following topics use the following terms: * Static: "stays the same" * Dynamic: "changing" In these situations, they may refer to the values in the specified list/table/menu or to the size of the list/table/menu. In these examples, the particularly distinctive (useful) feature of dynamic lists/tables/menus is that when they change in size, our code to create the HTML to display them, does not need to change. #### Example: Static (unchanging) list * Python List: ```{python} hobbies = ['exercising', 'baking', 'board games'] ``` * HTML Ordered (Numbered) List: ```{html} <ol> <li>exercising</li> <li>baking</li> <li>board games</li> </ol> ``` For an HTML Unordered (Bullet) List, replace `<ol>` with `<ul>` and `</ol>` with `</ul>`. * PyHTML generating an HTML Ordered List: ```{python} html( ol( li('exercising'), li('baking'), li('board games') ) ) ``` * And it could also be done like this: ```{python} hobby_list_pyhtml = ol( li('exercising'), li('baking'), li('board games')) html( hobby_list_pyhtml ) ``` * Or like this: ```{python} hobby_list_items_pyhtml = [li('exercising'), li('baking'), li('board games')] html( ol(hobby_list_items_pyhtml) ) ``` #### Example: Dynamic (changing) list Generating the HTML with Python (no PyHTML, just constructing the strings): ```{python} hobbies = ['exercising', 'baking', 'board games'] # Things may have changed the list in this time my_html = "<html><ol>" for hobby in hobbies: my_html += "<li>"+hobby+"</li>" my_html += "</li></html>" ``` Generating the HTML with Python using PyHTML: ```{python} hobbies = ['exercising', 'baking', 'board games'] # Things may have changed the list in this time hobbies_pyhtml = [] for hobby in hobbies: hobbies_pyhtml.append(li(hobby)) my_html = html( ol(hobbies_pyhtml) ) ``` The same thing can be applied (also dynamically) to dropdown menus and radio buttons. * Static dropdown menu: ```{python} html( form( select( option("A"), option("B"), option("C") ) ) ) ``` * Static radio buttons: ```{python} html( form( label("Option 1", input_(type="radio", name="group1")), label("Option 2", input_(type="radio", name="group1")) ) ) ``` ### Tables #### Example of static table Below is an example of a table of a set size. Notice how this table will always have 3 rows and 3 columns. We cannot simply change the `BOARD_SIZE` constant to cater for larger (or smaller) boards. ```{python} from pyhtml import html, head, body, title, table, tr, td BOARD_SIZE = 3 def main(): board = [] for i in range(BOARD_SIZE): row = [] for j in range(BOARD_SIZE): row.append('-') board.append(row) board[1][1] = 'X' board[1][0] = 'O' my_html = html( table( tr( td(board[0][0]), td(board[0][1]), td(board[0][2]) ), tr( td(board[1][0]), td(board[1][1]), td(board[1][2]) ), tr( td(board[2][0]), td(board[2][1]), td(board[2][2]) ) ) ) print(my_html) if __name__ == "__main__": main() ``` #### Example of dynamic table **Display a Tic Tac Toe board (list of lists) in a table** * How our board is created in Python: ```{python} board = [['-']*BOARD_SIZE]*BOARD_SIZE ``` * Produce the HTML using PyHTML: ```{python} board_rows_pyhtml = [] for row in board: row_pyhtml = [] for cell in row: row_pyhtml.append(td(cell)) board_rows_pyhtml.append(tr(row_pyhtml)) board_pyhtml = table(board_rows_pyhtml) ``` **Display our classes and tutors (dictionary) in a table** * Python directory structure: ```{python} tutors = {'M15A':'Will', 'T12A':'Liz', 'T12B':'Ellie', 'F12A':'Kai', 'F15A':'Krishne'} ``` * Produce the HTML using PyHTML: ```{python} from pyhtml import html, head, body, title, table, tr, td, th def main(): tutors = {'M15A':'Will', 'T12A':'Liz', 'T12B':'Ellie', 'F12A':'Kai', 'F15A':'Krishne'} table_rows_html = [] header_row = tr( th('Class'), th('Tutor') ) table_rows_html.append(header_row) for tute,tutor in tutors.items(): table_rows_html.append( tr(td(tute), td(tutor)) ) my_html = html( table( table_rows_html ) ) print(my_html) if __name__ == "__main__": main() ``` **Display our class timetable (list of dictionaries) in a table** * Python directory structure: ```{python} classes = [ {'class':'M15A', 'tutor':'Will', 'time':'Monday 3pm-6pm'}, {'class':'T12A', 'tutor':'Liz', 'time':'Tuesday 12pm-3pm'}, {'class':'T12B', 'tutor':'Ellie', 'time':'Tuesday 12pm-3pm'}, {'class':'F12A', 'tutor':'Kai', 'time':'Friday 12pm-3pm'}, {'class':'F15A', 'tutor':'Krishne', 'time':'Friday 3pm-6pm'} ] ``` * Produce the HTML using PyHTML: ```{python} from pyhtml import html, head, body, title, table, tr, td, th def main(): classes = [ {'class':'M15A', 'tutor':'Will', 'time':'Monday 3pm-6pm'}, {'class':'T12A', 'tutor':'Liz', 'time':'Tuesday 12pm-3pm'}, {'class':'T12B', 'tutor':'Ellie', 'time':'Tuesday 12pm-3pm'}, {'class':'F12A', 'tutor':'Kai', 'time':'Friday 12pm-3pm'}, {'class':'F15A', 'tutor':'Krishne', 'time':'Friday 3pm-6pm'} ] table_rows_html = [] header_row = tr( th('Class'), th('Tutor'), th('Time') ) table_rows_html.append(header_row) for tute in classes: table_rows_html.append(tr( td(tute['class']), td(tute['tutor']), td(tute['time']) )) my_html = html( table( table_rows_html ) ) print(my_html) if __name__ == "__main__": main() ``` ## Pitfalls - Each statement must be separated by a comma (except for the last one in the code block). For example: ```{python} form( label('Name: '), input_(type="text"), input_(type="submit", value="Go") ) ``` - Make sure that you reference any html terms you use in the `from pyhtml import html` you wrote at the top of the page ## References [PyHTML Reference](https://pypi.org/project/PyHTML/) [PyHTML Code](https://github.com/cenkalti/pyhtml/blob/master/pyhtml.py)