A sample skeleton showing the combination of AnPyLar and Flask. With the goal to show how a real full-stack Python application can be made.
The application does nothing really useful, but it shows how a login can be handled both on the client and on the server using Python and how logged users have access to a component which can only fetch info if logged in.
No database is used to keep users, as there is only one test user. This simplifies running and playing around with this skeleton.
Things are kept tidy using pipenv
which will install
anpylar
(as a development package only)flask
which is the core for the server side appflask-login
is used to control user managementuwsgi
in case you'd like to run the app directly with it
To get things ready do:
cd flaskpylar pipenv install --dev # to include development packages
The sample application has only one valid user with the following credentials
- Username:
test
- Password:
test
flaskpylar ... ├── app-manager.py ├── config_flaskpylar.py ├── config.py ├── Pipfile ├── Pipfile.lock ├── run.py ├── uwsgi.conf ├── uwsgi-run.py └── webignore
Holds the management scripts, requirement files and general and flaskpylar
specific configuration
flaskpylar ├── app ... ... │ ├── static │ ├── templates │ │ ├── index.html │ │ └── layout.html │ ├── __init__.py │ ├── api.py │ ├── app_loader.py │ ├── pyroes_management.py │ └── user_management.py ...
Things start out with a usual flask
layout: things are under the directory
app
. In this sample the server-side components are in
app/__init__.py
- Kickstarts the customFlask
object
app/pyroes_management.py
- dict holding Pyroes in place of a real database
app/user_management.py
- Classes and management forflask-login
app/api.py
- The API the client side components will use
app/app_loader.py
THE KEYIt generates a Flask Blueprint for each client side component. This is made here in a generic way and would probably needs specific Blueprints for specific needs of real world applications.
The core code in app/__init__.py
is:
# Load modules which define routes from . import api from . import app_loader # Set our default login view from . user_management import login_manager login_manager.login_view = '/users' app_loader.load_app('users', _login_to=True, url_prefix='/users') # Hint where to go after login app.config['LOGIN_TO'] = {'next': '/pyroes'} # Content blueprint app_loader.load_app('pyroes', _login_required=True, _local_template=True)
There are only 2 client side pages and each gets a Blueprint with
app_loader.load_app
. The Blueprint already understands the layout of the
client side applications on the disk (the templates account for the differences
if needed by checking the value of app.config['TESTING']
.
The chosen pattern on the server side was to create a Blueprint per component on the client side. The pattern here is:
- Each component is a complete AnPyLar module (or mini-application)
It fits the multi-page paradigm of working with Flask
. The usual pattern
for an AnPyLar only application is SPA
(Single Page Application) in
which a single AnPyLar module controls the entire routing and lifecycle of
components (it may of course foster sub-modules)
Everything is under the dev
directory:
flaskpylar ├── app │ ├── dev │ │ ├── apps │ │ │ ├── libs │ │ │ │ ├── api │ │ │ │ │ └── __init__.py │ │ │ │ ├── hello │ │ │ │ │ └── __init__.py │ │ │ │ └── __init__.py │ │ │ ├── pyroes │ │ │ │ ├── app │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── app_component.py │ │ │ │ │ └── app_module.py │ │ │ │ ├── static │ │ │ │ │ └── sample.jpg │ │ │ │ └── templates │ │ │ │ └── index.html │ │ │ └── users │ │ │ ├── app │ │ │ │ ├── __init__.py │ │ │ │ ├── app_component.css │ │ │ │ ├── app_component.html │ │ │ │ ├── app_component.py │ │ │ │ └── app_module.py │ │ │ └── static ... ... ...
As shown, each mini-application can have its own set of static
files and
templates
if needed be (the sample shows how the pyroes
mini-app uses
this facility)
The sample comes with a script called app-manager.py
which can be used to
manage the packaging and web-packaging of the application. It uses the commands
of the anpylar-cli
command family to do so (hence the need to have
anpylar
installed as a development package). See below the complete usage
help.
Although the app-manager
has several command line switches (see below for a
complete reference), there are three (3) common use cases
pipenv run ./app-manager --init
Creates the dev
directory where client side apps go and creates an initial
anpylar.js
bundle (non-optimized and with debug info enabled) inside.
This is meant to kick-start development and things will be run and tested usually with the command (see below for a longer explanation):
pipenv run ./run.py --debug
pipenv run ./app-manager
Takes the client side components inside the dev
directory, packages them
and moves them to the static
and templates
directory of the server side
application, in order for them to be delivered as if they were on the server.
This is meant for a close-to-production test of things and is usually meant to be run with the command (see below for a longer explanation):
pipenv run ./run.py --no-testing
pipenv run ./app-manager --webpack
This takes the already packed application and generates a bundle (optimized and
with no debug info) that can be taken for deployment to a server (with for
example a combination of nginx
and uwsgi
) The default directory for the
bundle is __webpack__
but can be given as __webpack__ DIRNAME
When webpacking the application manager pays attention to the patterns in the
file webignore
(usual shell wildcard patterns) to ignore any specified
pattern for inclusion in the webpack
During development run as:
pipenv run ./run.py --debug * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 144-058-227
This logs messages to the console and has Werkzeug also running in debug mode. Python files (and associated html/css files, should there be) for client side mini-applications will be fetched directly from the development directory.
The application can be packed (do not confuse with webpacking) to test how things would work on the production server. The usual sequence of commands will be:
pipenv run ./app-manager.py pipenv run ./run.py --not-testing # you may also add --debug if wished
When the application is webpacked, things are expected to be taken to a
production server, where you may run them with, for example, uwsgi
. The
provided configuration file can be matched to usual, for example, nginx
configurations.
$ ./run.py --help usage: run.py [-h] [--debug] [--no-testing] [--logging] [--flush] flaskyplar demo optional arguments: -h, --help show this help message and exit --debug run in debug mode (default: False) --no-testing disable testing mode (default: False) --logging log everything possible from wsgi (default: False)
Where:
--debug
(should actually be--development
) runs with debugging output enabled and directly from the sources--no-testing
runs the app from individual packaged files and expects static files /templates for client side components to be in the right directories (seeapp-manager
above)--logging
- does log the WSGI requests/responses
$ ./app-manager.py --help usage: app-manager [-h] [--init] [--webpack [WEBPACK]] [--keep-dev] [--web-ignore WEB_IGNORE] [--workdir WORKDIR] [--devdir DEVDIR] [--appsdir APPSDIR] [--outdir OUTDIR] [--clean-output] [--bundle-name BUNDLE_NAME] [--no-debug] [--no-optimize] [--no-bundle] [--no-paketize] [--quiet | --verbose] Flaskpylar paketizer optional arguments: -h, --help show this help message and exit --quiet, -q Remove output (errors will be reported) (default: False) --verbose, -v Increase verbosity level (default: False) Initialization options: --init Create dev dir and deploy bundle (default: False) WebPacking options: --webpack [WEBPACK] Create a deployment which packs everything except the contents of the development directory. If no argument is specified things are deployed to "__webpack__" (default: None) --keep-dev Keep dev directory contents in webpack (default: False) --web-ignore WEB_IGNORE Read patterns (unix-shell style) to ignore from the specified file. If not specified, then a file named webignore will be used if available (default: None) --web-debug The default for webpacking is to generate a bundle with no debugging. Use this option to enable it. Has precedence over the --no-debug flag (default: False) Directory/File Options: --workdir WORKDIR Override auto working directory detection (default: None) --devdir DEVDIR Development directory where to find sources (default: dev) --appsdir APPSDIR Apps directory under dev/output dir (default: apps) --outdir OUTDIR Base output directory under workdir (default: static) --clean-output Remove apps dir under output before starting (default: False) Bundle Generation: --bundle-name BUNDLE_NAME File Name for anpylar.js output (default: anpylar.js) --no-debug Generate no debug version of anpylar (default: False) --no-optimize Generate no debug version of anpylar (default: False) --no-bundle Skip generation of anpylar bundle (default: False) --no-paketize Skip paketization of apps (default: False)