subota, 21. siječnja 2017.

Comments on the Flask Mega-Tutorial Part 2 - Hello, World

OK, the boring part of setting up your Flask environment is done and you can start creating your first Flask web application, appropriatelly named Hello, World!

But before that :-) just a quick note about the Flask application project structure.Each non-trivial computer application has a structure. For such application there exists a directory structure, with files stored in particular directories depending on their usage, type and other parameters. This way a project is easier to develop and maintain.

Well, Flask - as many other applications - takes a step further. They follow the 'convention over configuration' philosophy. For instance, in a Flask application static files go into a directory named static and templates go into a directory named templates. The reason for this is that you, the application writer, don't have to worry about naming your directories - so less work for you configuring your project. This also means less work for the next guy that eventually takes on maintaining that beautiful web app you have created. He alredy knows where everything is, just by looking at directory names. And, finally, this also means less work for flask.

The first thing to do is to navigate to your microblog directory that you have created in the first part of the tutorial:

[anon@test ~]$ cd Documents/microblog
[anon@test microblog]$ 

And now, finally, directory creation time:

[anon@test ~]$ cd Documents/microblog
[anon@test microblog]$ mkdir app
[anon@test microblog]$ mkdir app/static
[anon@test microblog]$ mkdir app/templates
[anon@test microblog]$ mkdir tmp
[anon@test microblog]$ 

Let's see what the contents of our microblog directory look like:

[anon@test microblog]$ ls
app  flask  tmp
[anon@test microblog]$ 

Apart from the directories just created there is also the flask directory created by the venv command. To show you the current project structure in a nice hierarchical fashion I've installed the tree command and ran it:

[anon@test microblog]$ tree > /home/anon/Documents/flask_app_structure
[anon@test microblog]$ 

The greater than sign (>) means that I redirected tree output into a file named flask_app_structure in my Documents. Here is the flask_app_structure contents:

.
├── app
│   ├── static
│   └── templates
├── flask
│   ├── bin
│   │   ├── activate
│   │   ├── activate.csh
│   │   ├── activate.fish
│   │   ├── coverage
│   │   ├── coverage3
│   │   ├── coverage-3.6
│   │   ├── easy_install
│   │   ├── easy_install-3.6
│   │   ├── flask
│   │   ├── migrate
│   │   ├── migrate-repository
│   │   ├── pbr
│   │   ├── pip
│   │   ├── pip3
│   │   ├── pip3.6
│   │   ├── pybabel
│   │   ├── python -> /usr/bin/python
│   │   ├── python3 -> python
│   │   └── sqlformat
│   ├── include
│   ├── lib
│   │   └── python3.6
│   │       └── site-packages
│   │           ├── babel

...
...
...

│   ├── lib64 -> lib
│   ├── pip-selfcheck.json
│   └── pyvenv.cfg
└── tmp

408 directories, 3827 files

So the microblog/flask directory really contains a whole Python environment, ready for you to play with.

Now, to write some code, finally.

In your microblog/app directory create a new empty Python file named __init__.py  :

[anon@test microblog]$ > app/__init__.py
[anon@test microblog]$ 

What is happening here is that we are redirecting nothing to a file that doesn't exist and a new empty file is created in the microblog/app directory.
 
Those lines before and after init.py are actually double underscores and they have a special meaning in Python. They are used to denote Python 'magic' objects and you, the user should never use double underscores for your variable, function or file names. A file named __init__.py has a special meaning and you can read about it in the Python documentation.

Just to confirm that __init__.py has been created:

[anon@test microblog]$ ls ./app
__init__.py  static  templates
[anon@test microblog]$ 

When working in the terminal, the dot (.) refers to the current directory so with this command we are listing the contents of a directory named app that resides in our current directory - microblog. And, there it is - __init__.py has been created.

You can open the file in your favorite text editor to edit its contents. If you don't have a favorite programming editor, you can use what ever comes with your Linux distribution, like Gedit or Kate, or anything else really. The only two basic requirements are that the text you type in your editor is saved just the way you have typed it i.e. that your editor doesn't add any special characters to your files (in other words never use Libre Office Writer or MS Word as programming text editors). The other requirement is syntax highlighting, mening that different parts of your file have different colors. For instance, your keywords will be blue, comments green, variable names gray etc.

Before you open your file to edit you should make one last adjustment to your editor. In your editor menu find an entry named Preferences or Settings. When you open it there should be an option to set the tab key width. Set it to 4. Below it there should be a checkbox that, when checked, makes your editor replace tabs with spaces. In our case, each time you press the Tab key your editor will replace it with four spaces.

Python indents lines by four spaces. This is good form.

Now open the file and type in the Python code found in the original Flask tutorial:

from flask import Flask

app = Flask(__name__)
from app import views

and save the file. That's three lines of code, but there are still a few things that need explanation.

The first line: flask is a Python module you added to your Python installation earlier, using pip. What is Flask? If you look at the Flask documentation, you'll find out that Flask is the name of a class, and
Once it is created it will act as a central registry for the view functions, the URL rules, template configuration and much more.
The first line of our script imports the name Flask thus making it available to the script. Note that this very important object, the Flask instance, has not been created yet, you just made it available to your script - imported it.

The second line of the script does just that - it creates a Python object that is an instance of the Flask class and assigns it to a variable named app. Look again at the Flask documentation - the only thing you have to pass to Flask when creating its instance is an argument named import_name, all other arguments are optional. This means that if they are ommited they will be given default values.

In our script we use __name__ as import_name. __name__ is one of Python's special variables, representing the name of the module (script). As always, you can learn more about __name__ and other Python special  variables in the Python documentation.

Now the third line of the script. The tutorial says that:

The script above simply creates the application object (of class Flask) and then imports the views module, which we haven't written yet. Do not confuse app the variable (which gets assigned the Flask instance) with app the package (from which we import the views module).
I'm sure it'll sink in eventually so I'll just leave that one alone for now.

In Flask, responses to web requests are written as Python functions and are called views. Our views will always reside in the microblog/app/views.py file (remember the 'convention over configuration' motto). What a view looks like is (almost) up to you, the application author.

Let's create our views.py file:

[anon@test ~]$ cd Documents/microblog
[anon@test microblog]$ > app/views.py
[anon@test microblog]$ 

open it and type the view function code in:

from app import app

@app.route('/')
@app.route('index')
def index():
    return 'Hello, World!'


Remember the app variable that got assigned the Flask instance in your __init__.py? You are importing it right there in your first line. The package you are importing it from got its name from the directory name - microblog/app - hence the import app from app line. The variable name (app) is the same as the package name (app). You can learn more about Python modules and packages reading the documentaion.

Now on to the next two lines, beginning with the at sign (@). @ is a Python keyword that denotes a decorator,

... any callable Python object that is used to modify a function, method or class definition.
If you look at the Flask class documentation again, you'll see that Flask.route(rule, **options)is

a decorator that is used to register a view function for a given URL rule.
This means that the index() function that returns 'Hello, World' is executed every time a web browser requests your site root (/) or index (/index) page.

The last thing to do is to test your web application. In its root folder create a file named run.py:

[anon@test ~]$ cd Documents/microblog
[anon@test microblog]$ > run.py
[anon@test microblog]$ 

The code for run.py looks like this:


from app import app
app.run(debug=True))

Again you are importing a Flask class instance. Its run(host=None, port=None, debug=None, **options) method starts the development web server that comes with Flask and you are ready to test your application. In your terminal type:

[anon@test microblog]$ python run.py


and you will be greeted with a message like this:

 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 178-776-905

The important part here is the line with the http://127.0.0.1:5000/  part. If you type this address in your browser you will see a humble 'Hello, World!' message delivered by your index() function to your browser. If you type http://127.0.0.1:5000/index you will get the same message.  

That's not bad for a start, I guess.

ponedjeljak, 16. siječnja 2017.

Comments on the Flask Mega-Tutorial - Part 1 - Installation and Setup

The goal of the tutorial is to use Flask to create a microblogging web application and the first step is to set up your development environment. I am using Linux but Windows users can find setup instructions in the tutorial itself.

All Linux distributions I have used have Python installed by default. The reason for this is that some parts of the Linux infrastructure rely on Python scripts - this is a very important point that will affect the way you set up your Flask development environment.

The first thing you will need to do is to check your Python version. I want to learn Python 3 as the transition from Python 2 to Python 3 is well on its way, but Flask doesn't support all Python 3 versions. So, to check your default Python version, open your terminal and type:

[anon@test ~]$ python

This starts the interactive Python shell with its prompt:

Python 3.6.0 (default, Jan 16 2017, 12:12:55) 
[GCC 6.3.1 20170109] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

I am using Antergos, an Arch based Linux distibution and my defalut Python is 3.6.0. If I type:

[anon@test ~]$ python2

The prompt looks like this:

Python 2.7.13 (default, Dec 21 2016, 07:16:46) 
[GCC 6.2.1 20160830] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 

so I also have Python 2.7.13 available. On Debian based distributions, like Ubuntu, Linux Mint and others the situation is reverse: The default Python version is 2 so if you type python you start Python 2.7.x and if you type Python3 you start Python 3.

The first thing to do is to install Flask. Flask is distributed as a Python package and you can install it from your terminal using Python's pip command. As it is mentioned in the tutorial you don't want to install Flask (or any other random Python package) in your system Python environment. Instead, you install it using virtualenv.

Virtualenv is a Python tool that lets you create a copy of a Python installation in a directory that you choose. This is very handy as it lets you experiment with using Python packages - when you mess something up you can just delete your virtual environment and start over, without affecting your main installation. Let's start.

When you open your terminal, its working directory is your home directory (/home/anon). You can list the contents of the current directory using:

[anon@test ~]$ ls

ls stands for list, i.e. list the contents of the current directory. The output looks like this:

 ...
 Desktop
 Documents
 Downloads
 ...

You want to create your Flask project in your Documents directory, so type:

[anon@test ~]$ cd Documents
[anon@test Documents]$ mkdir microblog
[anon@test Documents]$ cd microblog
[anon@test microblog]$ 

cd stands for change directory and mkdir for make [new] directory. The result is that you created a directory named microblog in your Documents (/home/anon/Documents/microblog) and changed your working directory to it. Of course, at this point the microblog directory is still empty.

(Generally, it is a good thing when your Linux terminal doesn't respond to your commands. This means that all went well and there is nothing for the terminal to complain about.)

The next thing to do is to create your Python virtual environment. In the terminal , type:

[anon@test microblog]$ python -m venv flask

Let's break this command up. When invoked from the terminal Python can optionally accept a number of command line switches (or options) that affect its behaviour. If you type

[anon@test ~]$ python --help

Python lists all available command line switches. One of the switches is -m:

...
-m mod : run library module as a script (terminates option list)
...

So the command python -m mod[ule name] runs a Python module from the terminal. In our case the module name is venv, the module that lets you manage Python virtual environments.

The venv module itself also accepts command line arguments. You can list them by typing

[anon@test ~]$ python -m venv --help

The output is:

usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear]
            [--upgrade] [--without-pip] [--prompt PROMPT]
            ENV_DIR [ENV_DIR ...]
...

positional arguments:
  ENV_DIR               A directory to create the environment in.

...

Arguments enclosed in square brackets are optional. That is, the only argument that you have to pass to venv is ENV_DIR which specifies the directory in which your virtual environment will be created.

So, you can finally decipher the command that you used to create your virtual environment ([anon@test microblog]$ python -m venv flask): It invokes Python from the terminal to execute the venv module as a script and create a virtual environment in the specified directory (/home/anon/Documents/microblog/flask).

(I am lucky in that my version of Python - 3.6 - has the venv module installed by default. If you are running Python 2 you may need to use commands that are a little bit different than I listed above. The venv module is introduced in Python 3 and in Python 2 you will need to use virtualenv instead. You can find a few more details about this if you read this Stack Overflow thread.)

What dit the command actually do? It created a directory named flask in our microblog directory and copied your complete Python environment including the Python executable, pip and its site-packages. You can examine the flask directory contents by typing:

[anon@test microblog]$ find . -type f

The output is:

./flask/bin/easy_install
./flask/bin/easy_install-3.6
./flask/bin/activate.csh
./flask/bin/pip3
./flask/bin/pip
./flask/bin/pip3.6
./flask/bin/activate.fish
./flask/bin/activate
...
...
...
./flask/lib/python3.6/site-packages/setuptools/archive_util.py
./flask/lib/python3.6/site-packages/setuptools/package_index.py
./flask/lib/python3.6/site-packages/setuptools/cli-64.exe
./flask/lib/python3.6/site-packages/setuptools/cli.exe
./flask/lib/python3.6/site-packages/setuptools/windows_support.py
./flask/lib/python3.6/site-packages/setuptools/namespaces.py
./flask/lib/python3.6/site-packages/setuptools/cli-32.exe
./flask/lib/python3.6/site-packages/setuptools/version.py
./flask/lib/python3.6/site-packages/setuptools/dist.py

find is another Linux command that you can use from the terminal. You can try to find out what it does by typing:

[anon@test microblog]$ find -help

but the output is not very helpful. In Linux, though, there is another way to get help about commands. In your terminal type:

[anon@test microblog]$ man find. 

The output is much more helpful:

NAME
       find - search for files in a directory hierarchy

SYNOPSIS
       find  [-H]  [-L]  [-P]  [-D  debugopts]  [-Olevel]  [starting-point...]
       [expression]

DESCRIPTION
       This manual page documents the GNU version of find.  GNU find  searches
       the  directory  tree  rooted at each given starting-point by evaluating
       the given expression from left to right,  according  to  the  rules  of
       precedence  (see  section  OPERATORS),  until the outcome is known (the
       left hand side is false for and operations,  true  for  or),  at  which
       point  find  moves  on  to the next file name.  If no starting-point is
       specified, `.' is assumed.
...
...
...

man stands for manual and it displays Linux manual pages. You can even use:

[anon@test microblog]$ man man

to get help about the man[ual] command itself:

NAME
       man - an interface to the on-line reference manuals
...
DESCRIPTION
       man is the system's manual pager.  Each page argument given to  man  is
       normally  the  name of a program, utility or function.  The manual page
       associated with each of these arguments is then found and displayed.  A
       section,  if  provided, will direct man to look only in that section of
       the manual.  The default action is to search in all  of  the  available
       sections  following  a  pre-defined order ("1 n l 8 3 0 2 5 4 9 6 7" by
       default,   unless   overridden   by   the    SECTION    directive    in
       /etc/man_db.conf),  and to show only the first page found, even if page
       exists in several sections. 
...
...

find searches for files in a directory hierarchy. In our case the root directory given to find is our current directory - microblog - specified by the dot (.) and we only list files as specifid by the -type f parameter.

The next thing you need to do is install several Python modules related to flask. Before that you need to activate the virtual environment you just created so that you newly installed modules don't pollute your system Python environment. In your terminal - making sure that you are still in the /home/anon/Documents/microblog directory - type:

[anon@test microblog]$ source flask/bin/activate

If all goes well your terminal prompt should look like this:

(flask) [anon@test microblog]$

Note the (flask) part that appeared at the beginning of the prompt - this means that you have successfully activated your virtual environment. From now on all your commands like pip imports will affect your flask virtual environment rather than your system Python environment, so keep an eye at that (flask) part. To confirm this, type this at your command prompt:

(flask) [anon@test microblog]$ which python

The which command displays the location of the command you passed to it as the argument, in this case python. The output of which should look like this:

/home/anon/Documents/microblog/flask/bin/python

So, from now on you will really be working with a local copy of the Python executable.

To deactivate your flask virtual environment, type:

(flask) [anon@test microblog]$ deactivate

and your prompt changes back to:

[anon@test microblog]$

Don't deactivate it just yet, as we are about to import flask related Python modules.

(You can learn more about venv reading its documentation.)

And now, finally, you can use pip to install flask modules. At your terminal type the following commands one at a time:

(flask) [anon@test microblog]$ pip install flask
(flask) [anon@test microblog]$ pip install flask-login
(flask) [anon@test microblog]$ pip install flask-openid
(flask) [anon@test microblog]$ pip install flask-mail
(flask) [anon@test microblog]$ pip install flask-sqlalchemy
(flask) [anon@test microblog]$ pip install sqlalchemy-migrate
(flask) [anon@test microblog]$ pip install flask-whooshalchemy
(flask) [anon@test microblog]$ pip install flask-wtf
(flask) [anon@test microblog]$ pip install flask-babel
(flask) [anon@test microblog]$ pip install guess_language
(flask) [anon@test microblog]$ pip install flipflop
(flask) [anon@test microblog]$ pip install coverage

After each command pip will download the specified module with its dependencies and install it in your flask virtual environment. While doing this pip displays download and installation progress and any errors that may have ocurred during the installation. If all goes well you are set to go.

Well, that's about it, the tedious part of the tutorial is over and you can start having fun!


nedjelja, 8. siječnja 2017.

Comments on the Flask Mega-Tutorial - Part 0

I've decided to learn Flask, a web framework written in Python. To this end I've started to work through this tutorial:

 The Flask Mega-Tutorial

The tutorial is very well written and I had made some progress, but here is the thing: It was not just Flask that I was learning. I had to learn about web programming (HTML, ...), Python 3, Linux Bash, MVC pattern and many other things in parallel.This proved overwhelming, so I have decided to restart the tutorial, this time documenting my progress and noting all the little things I have learned.

So, let's get started, hoping that I will be able to use these posts for my reference and also that they would be useful to other people learning Flask web programming.