Why this?
I found myself working on yet another python web application, copying some stuff from the previous one, improving it a bit and wondering if now is the time to create that great example project to make life easier next time.
I am starting this without knowing exactly where it will end, but I imagine a basic single page application with complete build and installation scripts for Linux, Docker and Kubernetes.
In this post
In this post I will create a small python project that can render a page in a browser - like Hello World for web apps. This will be the foundation for the next, soon to follow post. Stay tuned!
Source on GitHub
Source for this post in on branch post_1 on https://github.com/stefanmeisner/single_page_python
Here we go!
There are a number of web frameworks for python out there. I have stumbled into Flask a number of times. It's quite minimalistic compared to for example Django, and you're up and running in a very few lines of code.
Flask comes along with Jinja2 templating engine], another of my favorite tools.
Project layout
First things first - I have googled around and experimented too, until I settled with this project layout, which is quite common I believe.
If you are used to setup.py and requirements.txt this may be new for you. Welcome to the world of pyproject.toml!
I have found the following project layout to work well for me:
single_page_python/
README.md
LICENSE
.gitignore
pyproject.toml
src/
single_page_python.py
single_page_python/
__init__.py
server.py
templates/
index.html.j2
Quick walk-through of the project files
pyproject.toml
I have not experimented with other build systems than setuptools, it has worked well for me so far. Dependencies goes into "dependencies" in the project section, and in the last section there is a list of development dependencies, required to build the project. This is also where you would add pytest and other stuff that should not be part of the shipped application.
[build-system]
requires = ["setuptools >= 80", "setuptools-scm", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "single_page_python"
version = "0.0.1"
description = "Single Page Web Application with Python and JavaScript"
authors = [
{name = "Stefan Meisner Larsen", email="developer@meisner-larsen.dk"}
]
readme = "README.md"
requires-python = ">=3.11"
dependencies = ["flask"]
[project.optional-dependencies]
dev = ["build"]
server.py - the interesting stuff :)
We start by creating a Flask app - an instance of the class Flask, stating the name of our module as argument.
Using the app.route as decorator, we can easily specify, that any request for '/' should be handled by the index() method.
The render_template() function takes the name of a jinja2 template located in 'templates' folder, relative to server.py.
The 'title' argument is a context variable, that will be passed to the jinja template.
Let's take a look at that!
# Copyright 2025 Stefan Meisner Larsen
# Licensed under the MIT License.
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html.j2', title='Single Page Web Application')
def start_server():
app.run(debug=True, host="localhost")
templates/index.html.j2
The naming of this file, with double extension, makes it possible to provide syntax highlighting for both Jinja and HTML (at least in vscode, I did not get it to work here). Look how the 'title' argument to render_template() is being used:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h5>{{ title }}</h5>
</body>
</html>
single_page_python.py - Where it all begins
This is the application entry point, the python file that you will actually be executing.
from single_page_python.server import start_server
if __name__ == '__main__':
start_server()
Creating a virtual environment for our project
Before installing any packages, we will create a virtual python environment ".venv" in the project root. The virtual environment is an isolated python installation, This will ensure that we don't tamper with the global python installation. On my linux system, the global python interpreter is called python3. We use the global interpreter to create the virtual environment.
After creating the environment, don't forget to activate it. This is done by "sourcing" the activate script using ".":
python -m venv .venv
. .venv/bin/activate
Running the application
In the project root (where pyproject.tom is) install the application and the required dependencies:
python -m pip install -e '.[dev]'
Then run it with:
python src/single_page_python.py
Try it out here http://localhost:5000!
Top comments (0)