|
1 | 1 | """ |
2 | | -# PyHTML Enhanced |
| 2 | +# `<PyHTML/>` |
3 | 3 |
|
4 | 4 | A library for building HTML documents with a simple and learnable syntax, |
5 | 5 | inspired by (and similar to) |
6 | 6 | [Cenk Altı's PyHTML library](https://github.com/cenkalti/pyhtml), but |
7 | 7 | with improved documentation and type safety. |
8 | 8 |
|
| 9 | +Learn more by reading [the documentation](https://comp1010unsw.github.io/pyhtml-enhanced/). |
| 10 | +
|
9 | 11 | ## Features |
10 | 12 |
|
11 | 13 | * Inline documentation and type safety for all tags. |
|
16 | 18 |
|
17 | 19 | * No dependencies. |
18 | 20 |
|
19 | | -* 100% test coverage |
| 21 | +* 100% test coverage. |
20 | 22 |
|
21 | 23 | ## Usage |
22 | 24 |
|
|
45 | 47 | <h1> |
46 | 48 | Hello, world! |
47 | 49 | </h1> |
48 | | - <p> |
49 | | - This is my amazing website! |
50 | | - </p> |
| 50 | + <p>This is my amazing website!</p> |
51 | 51 | </body> |
52 | 52 | </html> |
53 | 53 |
|
54 | 54 | ``` |
55 | | -
|
56 | | -### Creating elements |
57 | | -
|
58 | | -Every HTML tag is represented by a `class` that generates that HTML code. For |
59 | | -example, to create a `<br>` element, you could use: |
60 | | -
|
61 | | -```py |
62 | | ->>> line_break = p.br() |
63 | | ->>> print(str(line_break)) |
64 | | -<br/> |
65 | | -
|
66 | | -``` |
67 | | -
|
68 | | -### Adding children to elements |
69 | | -
|
70 | | -Any arguments to a tag are used as a child element to the created HTML element. |
71 | | -For example, to create a heading with the text `"My awesome website"`, you |
72 | | -could use |
73 | | -
|
74 | | -```py |
75 | | ->>> heading = p.h1("My awesome website") |
76 | | ->>> print(str(heading)) |
77 | | -<h1> |
78 | | - My awesome website |
79 | | -</h1> |
80 | | -
|
81 | | -``` |
82 | | -
|
83 | | -### Adding attributes to elements |
84 | | -
|
85 | | -Any keyword arguments to a tag are used as an attribute of the created HTML |
86 | | -element. For example, to create a form submit button, you could use |
87 | | -
|
88 | | -```py |
89 | | ->>> submit_button = p.input(type="submit") |
90 | | ->>> print(str(submit_button)) |
91 | | -<input type="submit"/> |
92 | | -
|
93 | | -``` |
94 | | -
|
95 | | -### Adding attributes and children |
96 | | -
|
97 | | -In HTML, attributes are specified within the opening tag. Contrastingly, Python |
98 | | -requires keyword arguments (attributes) to be specified after regular arguments |
99 | | -(children). To maintain similarity to writing regular HTML, you can call an |
100 | | -element in order to add more attributes and children. For example, to create |
101 | | -a link to PyHTML's GitHub page, you could use |
102 | | -
|
103 | | -```py |
104 | | ->>> my_link = p.a(href="https://github.com/COMP1010UNSW/pyhtml-enhanced")("Take a look at the code") |
105 | | ->>> print(str(my_link)) |
106 | | -<a href="https://github.com/COMP1010UNSW/pyhtml-enhanced"> |
107 | | - Take a look at the code |
108 | | -</a> |
109 | | -
|
110 | | -``` |
111 | | -
|
112 | | -### HTML comments |
113 | | -
|
114 | | -You can add comments to HTML (useful for debugging) by using the `Comment` tag. |
115 | | -
|
116 | | -```py |
117 | | ->>> comment = p.Comment("This is an HTML comment") |
118 | | ->>> print(str(comment)) |
119 | | -<!-- |
120 | | - This is an HTML comment |
121 | | ---> |
122 | | -
|
123 | | -``` |
124 | | -
|
125 | | -### Rendering HTML |
126 | | -
|
127 | | -Converting your PyHTML into HTML is as simple as stringifying it! |
128 | | -
|
129 | | -```py |
130 | | ->>> print(str(p.i("How straightforward!"))) |
131 | | -<i> |
132 | | - How straightforward! |
133 | | -</i> |
134 | | -
|
135 | | -``` |
136 | | -
|
137 | | -### Custom tags |
138 | | -
|
139 | | -Since this library includes all modern HTML tags, it is very unlikely that |
140 | | -you'll need to do create a custom tag. However if you really need to, you can |
141 | | -create a class deriving from `Tag`. |
142 | | -
|
143 | | -```py |
144 | | ->>> class fancytag(p.Tag): |
145 | | -... ... |
146 | | ->>> print(fancytag()) |
147 | | -<fancytag></fancytag> |
148 | | -
|
149 | | -``` |
150 | | -
|
151 | | -#### Tag base classes |
152 | | -
|
153 | | -You can derive from various other classes to get more control over how your tag |
154 | | -is rendered: |
155 | | -
|
156 | | -* `Tag`: default rendering. |
157 | | -
|
158 | | -* `SelfClosingTag`: tag is self-closing, meaning that no child elements are |
159 | | - accepted. |
160 | | -
|
161 | | -* `WhitespaceSensitiveTag`: tag is whitespace-sensitive, meaning that its |
162 | | - child elements are not indented. |
163 | | -
|
164 | | -#### Class properties |
165 | | -
|
166 | | -* `children`: child elements |
167 | | -* `attributes`: element attributes |
168 | | -
|
169 | | -#### Rendering control functions |
170 | | -
|
171 | | -You can also override various functions to control the existing rendering. |
172 | | -
|
173 | | -* `_get_tag_name`: return the name to use for the tag. For example returning |
174 | | - `"foo"` would produce `<foo>`. |
175 | | -
|
176 | | -* `_get_default_attributes`: return the default values for attributes. |
177 | | -
|
178 | | -* `_get_tag_pre_content`: return the pre-content for the tag. For example, the |
179 | | - `<html>` tag uses this to add the `<!DOCTYPE html>` before the opening tag. |
180 | | -
|
181 | | -* `_escape_children`: return whether the string child elements should be |
182 | | - escaped to prevent HTML injection. |
183 | | -
|
184 | | -* `_render`: render the element and its children, returning the list of lines |
185 | | - to use for the output. Overriding this should be a last resort, as it is easy |
186 | | - to subtly break the rendering process if you aren't careful. |
187 | | -
|
188 | | -Refer to the documentation for `Tag` for more information. |
189 | | -
|
190 | | -## Differences to PyHTML |
191 | | -
|
192 | | -There are some minor usage differences compared to the original PyHTML library. |
193 | | -
|
194 | | -Uninstantiated classes are only rendered if they are given as the child of an |
195 | | -instantiated element. |
196 | | -
|
197 | | -```py |
198 | | ->>> p.br |
199 | | -<class 'pyhtml.__tags.generated.br'> |
200 | | ->>> print(str(p.html(p.body(p.br)))) |
201 | | -<!DOCTYPE html> |
202 | | -<html> |
203 | | - <body> |
204 | | - <br/> |
205 | | - </body> |
206 | | -</html> |
207 | | -
|
208 | | -``` |
209 | | -
|
210 | | -Calling an instance of a `Tag` will return a new tag containing all elements of |
211 | | -the original tag combined with the new attributes and children, but will not |
212 | | -modify the original instance, as I found the old behaviour confusing and |
213 | | -bug-prone. |
214 | | -
|
215 | | -```py |
216 | | ->>> para = p.p("Base paragraph") |
217 | | ->>> para2 = para("Extra text") |
218 | | ->>> para2 |
219 | | -<p> |
220 | | - Base paragraph |
221 | | - Extra text |
222 | | -</p> |
223 | | ->>> para |
224 | | -<p> |
225 | | - Base paragraph |
226 | | -</p> |
227 | | -
|
228 | | -``` |
229 | | -
|
230 | | -## Known issues |
231 | | -
|
232 | | -There are a couple of things I haven't gotten round to sorting out yet |
233 | | -
|
234 | | -* [ ] Add default attributes to more tags |
235 | | -* [ ] Some tags (eg `<pre>`, `<script>`) currently aren't properly implemented |
236 | | - and escape their contents. |
237 | | -
|
238 | | -## How it works |
239 | | -
|
240 | | -Since there are so many HTML tags, it would be extremely tedious to document |
241 | | -them all manually. In the `meta` directory, you will find code that solves this |
242 | | -problem with the following steps: |
243 | | -
|
244 | | -1. Download the Markdown source for |
245 | | - [MDN's documentation of all HTML elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element). |
246 | | -
|
247 | | -2. Parse the markdown to gather all tag names and descriptions, discarding |
248 | | - garbage data and obsolete tags. |
249 | | -
|
250 | | -3. Use data from a YAML configuration file ([`meta/tags.yml`](meta/tags.yml)) |
251 | | - to gather information on suggested attributes and base classes to use for |
252 | | - each tag. |
253 | | -
|
254 | | -4. Generate Python code to represent all of these tags, including their |
255 | | - documentation. |
256 | | -
|
257 | | -## Credits |
258 | | -
|
259 | | -### [Cenkalti/PyHTML](https://github.com/cenkalti/pyhtml) |
260 | | -
|
261 | | -Cenk Altı's work was used as a source of inspiration and reference. Although |
262 | | -all the code in `pyhtml-enhanced` was written by me, I want to thank them for |
263 | | -the significant help their hard work provided while creating this project, |
264 | | -going as far as to give design advice on request. |
265 | | -
|
266 | | -### [MDN Web Docs](https://developer.mozilla.org/en-US/) |
267 | | -
|
268 | | -Almost all of the documentation was gathered from the MDN Web Docs. It's super |
269 | | -neat that all their documentation is open (licensed as |
270 | | -[CC-BY-SA-2.5](https://creativecommons.org/licenses/by-sa/2.5/) if you're |
271 | | -interested). |
272 | | -
|
273 | | -### COMP1010 students and staff |
274 | | -
|
275 | | -COMP1010's students and staff members have uncovered and helped to resolve many |
276 | | -bugs, and have suggested many improvements. I'd like to thank them for all of |
277 | | -their help! |
278 | | -
|
279 | | -## License |
280 | | -
|
281 | | -### Source code |
282 | | -
|
283 | | -Copyright (c) 2023 Maddy Guthridge, COMP1010 UNSW |
284 | | -
|
285 | | -Source code for the library is open source, using the |
286 | | -[MIT license](https://choosealicense.com/licenses/mit/). A copy of the license |
287 | | -text is available in [LICENSE.md](https://github.com/COMP1010UNSW/pyhtml-enhanced/blob/main/LICENSE.md) |
288 | | -
|
289 | | -### Documentation |
290 | | -
|
291 | | -Documentation is copied from MDN Web Docs, and is license under |
292 | | -[CC-BY-SA-2.5](https://creativecommons.org/licenses/by-sa/2.5/). A copy of the |
293 | | -license text is available in [LICENSE_DOCS.md](https://github.com/COMP1010UNSW/pyhtml-enhanced/blob/main/LICENSE_DOCS.md) |
294 | 55 | """ |
295 | 56 |
|
296 | 57 | # Disable Flake8, since it really doesn't like our docstring above |
|
0 commit comments