Compare commits

..

2 commits

Author SHA1 Message Date
c7da7e32b7 Added simple web page, routes are in a separate file 2023-02-15 17:34:49 +04:00
9ead8a457c Improved structure
- Flask app factory instead of initializing `app` variable
- Gunicorn for production server
- Makefile: python3 -m
- .gitignore: instance dir
2023-02-15 16:00:30 +04:00
14 changed files with 192 additions and 19 deletions

1
.gitignore vendored
View file

@ -2,6 +2,7 @@ __pycache__/
.mypy_cache/ .mypy_cache/
venv/ venv/
instance/
.vscode/ .vscode/
.idea/ .idea/

View file

@ -1,8 +1,8 @@
dev: dev:
FLASK_DEBUG="true" flask run FLASK_DEBUG="true" python3 -m flask run
prod: prod:
flask run python3 -m gunicorn -w 4 "app:create_app()"
format: format:
python3 -m autopep8 -r --in-place flaskapp/ python3 -m autopep8 -r --in-place flaskapp/

2
app.py
View file

@ -1 +1 @@
from flaskapp.app import app from flaskapp.app import create_app

View file

@ -1,3 +0,0 @@
"""Init file for the module"""
from .app import app

View file

@ -1,20 +1,39 @@
"""Flask web application """Flask web application main script"""
main script"""
from pathlib import Path import os
import secrets
from flask import Flask from flask import Flask
from . import routes
from . import errors
root = Path('..')
static = str(root / 'static')
tmpl = str(root / 'templates')
def create_app() -> Flask:
"""Flask app factory function"""
# Create an app object
app = Flask( app = Flask(
'${REPO_NAME_SNAKE}', __name__,
static_folder=static, static_folder='../static',
template_folder=tmpl, template_folder='../templates',
instance_relative_config=True,
)
# Get the token from environment
# or generate it using secrets
app.config['SECRET_KEY'] = os.getenv(
'SECRET_KEY',
secrets.token_hex(32),
) )
if __name__ == '__main__': # Create instance/ directory
app.run() try:
os.makedirs(app.instance_path)
except OSError:
pass
# Add routes
routes.add_routes(app)
errors.add_routes(app)
return app

48
flaskapp/errors.py Normal file
View file

@ -0,0 +1,48 @@
"""Flask app error handlers"""
from pathlib import Path
from flask import Flask
from flask import render_template
# Add other HTTP error codes here
CODES = [404, 500]
def add_routes(app: Flask) -> None:
"""Add all error handlers
Args:
app (Flask): Flask application
"""
tmpl_dir = app.template_folder
if tmpl_dir is None:
return
tmpl = Path(__file__).parent / tmpl_dir
for code in CODES:
add_handler(app, tmpl, code)
def add_handler(
app: Flask,
tmpl: Path,
code: int) -> None:
"""Add Flask app error handler.
Only for internal use
Args:
app (Flask): Flask application
file (str): Template filename
code (int): Error code
"""
file = f'{code}.html'
if (tmpl / file).exists():
@app.errorhandler(code)
def handler(_e):
return render_template(file), code

16
flaskapp/routes.py Normal file
View file

@ -0,0 +1,16 @@
"""Main Flask app routes"""
from flask import Flask
from flask import render_template
def add_routes(app: Flask) -> None:
"""Add main routes
Args:
app (Flask): Flask application
"""
@app.route('/')
def index():
return render_template('index.html')

View file

@ -1 +1,2 @@
flask==2.2.2 flask==2.2.2
gunicorn==20.1.0

31
static/css/style.css Normal file
View file

@ -0,0 +1,31 @@
body {
height: 100vh;
padding: 0;
margin: 0;
font-family: sans-serif;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
background: #fff;
color: #000;
}
@media (prefers-color-scheme: dark) {
body {
background: #202023;
color: #eee;
}
}
header { margin-top: 5px; }
footer { margin-bottom: 5px; }
a {
color: #5b8a55;
}
a:hover {
filter: brightness(120%);
}

4
static/js/script.js Normal file
View file

@ -0,0 +1,4 @@
addEventListener('load', () => {
document.getElementById('js')
.innerText = new Date().toLocaleString()
})

11
templates/404.html Normal file
View file

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% block title %}404{% endblock %}
{% block content %}
<h1>404: Not Found</h1>
<p>
Go to the
<a href="/">main page</a>
</p>
{% endblock %}

15
templates/500.html Normal file
View file

@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block title %}500{% endblock %}
{% block content %}
<h1>500: ISE</h1>
<p>
An error occured while
processing your request.
</p>
<p>
Please, try again later
or contact web site admin.
</p>
{% endblock %}

18
templates/base.html Normal file
View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="${REPO_DESCRIPTION}">
<title>{% block title %}{% endblock %} | ${REPO_NAME}</title>
<link rel="stylesheet" href="/static/css/style.css">
<script src="/static/js/script.js"></script>
</head>
<body>
<header>${REPO_NAME}</header>
<article>
{% block content %}{% endblock %}
</article>
<footer id="js"></footer>
</body>
</html>

12
templates/index.html Normal file
View file

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block title %}Main page{% endblock %}
{% block content %}
<h1>
This is the default main page of
<a href="https://git.dc09.ru/DarkCat09/tmpl-flask">
Flask app template
</a>
</h1>
{% endblock %}