Python Hypertext Markup Language - Extension of HTML
Project description
Python Hypertext Markup Language (phml)
TOC
Overview
The idea behind the creation of Python in Hypertext Markup Language (phml), is to allow for web page generation with direct access to python. This language pulls directly from frameworks like VueJS. There is conditional rendering, components, python elements, inline/embedded python blocks, and much more. Now let's dive into more about this language.
Let's start with the new python
element. Python is a whitespace language. As such phml
has the challenge of maintaining the indentation in an appropriate way. With phml, I have made the decision to allow you to have as much leading whitespace as you want as long as the indentation is consistent. This means that indentation is based on the first lines offset. Take this phml example:
<python>
if True:
print("Hello World")
</python>
This phml python block will adjust the offset so that the python is executed as seen below:
if True:
print("Hello World")
So now we can write python code, now what? You can define functions and variables
how you normally would and they are now available to the scope of the entire file.
Take, for instance, the example from above, the one with py-src="urls('youtube')"
.
You can define the URL
function in the python
element and it can be accessed in an element. So the code would look like this:
<python>
def URL(link: str) -> str:
links = {
"youtube": "https://youtube.com"
}
if link in links:
return links[link]
else:
return ""
</python>
...
<a href="{URL('youtube')}">Youtube</a>
phml combines all python
elements and treats them as a python file. All local variables and imports are parsed and stored so that they may be accessed later. With that in mind that means you have the full power of the python programming language.
Next up is inline python blocks. These are represented with {}
. Any text in-between the brackets will be processed as python. This is mostly useful when you want to inject a value from python. Assume that there is a variable defined in the python
element called message
and it contains Hello World!
. Now this variable can be used like this, <p>{ message }</p>
,
which renders to, <p>Hello World!</p>
.
Note: Inline python blocks are only rendered in a Text element or inside an html attribute.
Multiline blocks are a lot like inline python blocks, but they also have some differences. You can do whatever you like inside this block, however if you expect a value to come from the block you must have at least one local variable. The last local variable defined in this block is used at the result/value.
Conditional Rendering with py-if
, py-elif
, and py-else
is an extremely helpful tool in phml.
py-if
can be used alone and that the python inside it's value must be truthy for the element to be rendered. py-elif
requires an element with a py-if
or py-elif
attribute immediately before it, and it's condition is rendered the same as py-if
but only rendered if a py-if
or py-elif
first
fails. py-else
requires there to be either a py-if
or a py-else
immediately before it. It only
renders if the previous element's condition fails. If py-elif
or py-else
is on an element, but
the previous element isn't a py-if
or py-elif
then an exception will occur. Most importantly, the first element in a chain of conditions must be a py-if
. For ease of use, instead of writing py-if
, py-elif
, or py-else
can be written as @if
, @elif
, or @else
respectively.
Other than conditions, there is also a built in py-for
attribute. Any element with py-for will take a python for-loop expression that will be applied to that element. So if you did something like this:
<ul>
<li py-for='i in range(3)'>
<p>{i}</p>
</li>
</ul>
The compiled html will be:
<ul>
<li>
<p>1</p>
</li>
<li>
<p>2</p>
</li>
<li>
<p>3</p>
</li>
</ul>
The for
and :
in the for loops condition are optional. So you can combine for
, i in range(10)
, and :
or leave out for
and :
at your discretion. py-for
can also be written as @for
.
Python attributes are shortcuts for using inline python blocks in html attributes. Normally, in
phml, you would inject python logic into an attribute similar to this: src="{url('youtube')}"
. If you would like to make the whole attribute value a python expression you may prefix any attribute with a py-
or :
. This keeps the attribute name the same after the prefix, but tells
the parser that the entire value should be processed as python. So the previous example can also be expressed as py-src="URL('youtube')"
or :src="URL('youtube')"
.
This language also has the ability to convert back to html and json with converting to html having more features. Converting to json is just a json representation of a phml ast. However, converting to html is where the magic happens. The compiler executes python blocks, substitutes components, and processes conditions to create a final html string that is dynamic to its original ast. A user may pass additional kwargs to the compiler to expose additional data to the execution of python blocks. If you wish to compile to a non supported language the compiler can take a callable that returns the final string. It passes all the data; components, kwargs, ast, etc… So if a user wishes to extend the language thay may.
:warning: This language is in early planning and development stages. All forms of feedback are encouraged.
How to use
PHML is in early planning so the use is limited.
The current version is able to parse phml using an html parser. This creates a phml ast which then can be converted back to phml for to json. Converting to html is coming soon, but will take type since that is the core functionality of this language. It will need to parse, execute, and handle imbedded python code.
Use
PHML provides file type variables for better ease of use. The types include HTML
, PHML
, and JSON
. They can be imported with from phml import HTML, PHML, JSON
.
First import the PHMLCore, from phml import PHMLCore
. Then you can do the following:
core = PHMLCore().load("path/to/file.phml")
print(core.render())
By default PHMLCore.render()
will return the html
string. If you want to get a json
string you may pass the file type variable JSON
. PHMLCore.render(file_type=JSON)
.
If you want to write to a file you can call core.write("path/to/output/file.phml")
. Same with render
it defaults to html. You can change this the same way as render
. core.write("path/to/otuput/file.json", file_type=JSON)
.
For both render
and write
you will first need to call core.load("path/to/source/file.phml")
. This parses the source file and stores the ast in the parser. render
and write
then use that ast to create the desired output. Optionally if you already have
a phml or html string or a properly formatted dict you can call core.parse(data)
which will parse that information similar to load
.
core.render
and core.write
return self
which allows for method chaining. See the examples in example/
to see how this can be used.
Every time core.parse
or core.load
is called it will overwrite the stored ast variable.
For more information check out the API Docs
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file phml-0.1.1.tar.gz
.
File metadata
- Download URL: phml-0.1.1.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.10.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3df671d7a1d6c568504584107ed8bf87fcd026c2ce6edb3c7a1c512bc7bb6ea4 |
|
MD5 | e8ff97c55114a241326cd4c314d6bfa6 |
|
BLAKE2b-256 | de62e6bd57a3adc26a1cf91d9a82652ebedd1e1f389f3f9fee0badde48b84b9f |
File details
Details for the file phml-0.1.1-py3-none-any.whl
.
File metadata
- Download URL: phml-0.1.1-py3-none-any.whl
- Upload date:
- Size: 61.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.10.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0d37ec4ffbf5b5c37df0396795674aaedce4257caff93651708d819c608cd7ae |
|
MD5 | 85b7ccfcca91fd60fc44339ed63fb921 |
|
BLAKE2b-256 | e823d81c1af99405838c31971c0801cf346b10d8cd1d920d54a2744c696a9999 |