Python - Abstract View
I have a really simple abstract-view package on packagist that allows me to
do some really basic templating and create some "view objects". A need arose to do a similar thing with Python, so here we go.
Steps
First, we created an AbstractVIew class. It appears that Python doesn't have a native concept for abstract classes, so we make use of the Abstract Base Classes (ABC) Python library.
AbstractView.py
from string import Template
from abc import ABC, abstractmethod
class AbstractView(ABC):
@abstractmethod
def getTemplateString(self):
pass
def __str__(self):
return Template(self.getTemplateString()).substitute(self.__dict__)
As you can see, this is really just a case of running the
Python3 string template functionality around an abstract method to get the template string.
It substitutes the classe's properties into the template string before being returned. By overriding the __str__
method, we ensure this
is what is returned when a user tried to print or get the string representation of our object.
MyView.py
Below is a really basic example of a view that makes use of the AbstractView class we just created. This represents an email you might
be sending to someone. This is as easy as declaring our properties (making use of
dataclasses so we don't have to write the constructor),
and filling in the getTemplateString
abstract method, to return the template.
from AbstractView import AbstractView
from dataclasses import dataclass
@dataclass
class MyView(AbstractView):
rate: str
name: str
contact_email: str
date_string: str
def getTemplateString(self):
return """Dear ${name},
We would like to inform you that
our rate is going to increase to £${rate} per hour on the ${date_string}.
If you have any questions or concerns, please email us at ${contact_email}.
Sincerely,
Harry"""
When executed with:
print(MyView("5.00", "Bob", "support@mydomain.com", "5th of November"))
... you get the following output:
Dear Bob,
We would like to inform you that
our rate is going to increase to £5.00 per hour on the 5th of November.
If you have any questions or concerns, please email us at support@mydomain.com.
Sincerely,
Harry
MyDockerComposeView.py
Sometimes, we our templates actually need to contain the ${xxx}
pattern, and not be substituted. For example, if we wish to output a Docker Compose file that is
expecting environment variables to be substituted at the last second. In such a case, we can escape the $
by using $$
like so:
from AbstractView import AbstractView
from dataclasses import dataclass
@dataclass
class MyDockerComposeView(AbstractView):
registry: str
project_name: str
def getTemplateString(self):
return """version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: app
image: ${registry}/${project_name}
restart: always
environment:
- FOO=$${FOO}
- BAR=$${BAR}
"""
When executed with:
print(MyDockerComposeView("registry.mydomain.com", "project1"))
... you get the following output:
version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: app
image: registry.mydomain.com/project1
restart: always
environment:
- FOO=${FOO}
- BAR=${BAR}
As you can see, the FOO and BAR environment variable declarations came out correctly, and will get substituted at the last second with Docker Compose.
main.py
For completeness, here is a main.py one can use to complete the codebase.
from MyView import MyView
from MyDockerComposeView import MyDockerComposeView
if __name__ == '__main__':
myEmailView = MyView("5.00", "Bob", "support@mydomain.com", "5th of November")
myDockerComposeFIle = MyDockerComposeView("registry.programster.org", "blog")
print(myEmailView)
If you wish, you can download a zip file of the entire example codebase.
First published: 2nd March 2022