How to Package and Run Python Flask application using Poetry

How to Package and Run Python Flask application using Poetry

python_poetry_flask_package

Here in this article we will see how we can install Python Poetry a Packaing and Dependency managment software. We will convert an existing Flask based application into a package using Poetry and Validate it.

Test Environment

Fedora workstation 38

What is Python Poetry

Python Poetry helps in packaging and managing the dependencies in an easy way. We can develop our python application by adding the required dependencies in an easy way. Once the necessary dependencies are added, we can build our project and package the resulting artifacts using a single command. Poetry takes care of managing the dependencies (ie. install/update) as per our declaration. This package can further be published to PyPI repository for other to use it.

The only requirement for Poetry is Python 3.7+.

Procedure

Step1: Install Poetry

This package can be installed using multiple ways as stated in the documentation. Here are we are going to use the Offical Installer script to download and install the Poetry package on our linux system.

[admin@fedwor38 ~]$ curl -sSL https://install.python-poetry.org | python3 -
Retrieving Poetry metadata

# Welcome to Poetry!

This will download and install the latest version of Poetry,
a dependency and package manager for Python.

It will add the `poetry` command to Poetry's bin directory, located at:

/home/admin/.local/bin

You can uninstall at any time by executing this script with the --uninstall option,
and these changes will be reverted.

Installing Poetry (1.5.1): Done

Poetry (1.5.1) is installed now. Great!

You can test that everything is set up by executing:

`poetry --version`

So as you can see from the output, Poetry by default is installed into the user-speocfic directory. We can also get the exact location using the whereis command as shown below.

[admin@fedwor38 ~]$ whereis poetry
poetry: /home/admin/.local/bin/poetry

By default Poetry’s bin directory is also added to the Linux $PATH variable as shown below.

[admin@fedwor38 ~]$ echo $PATH
/home/admin/.local/bin:/home/admin/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

We can verify the version of the Poetry that is installed as shown below.

[admin@fedwor38 ~]$ poetry --version
Poetry (version 1.5.1)

Enable tab completetion for bash shell as shown below.

[admin@fedwor38 ~]$ poetry completions bash >> ~/.bash_completion

Step2: Create a New Poetry Project

Here we are going to create a new Poetry Project as shown below. From the directory structure you can see that it has created a flaskapp python package. The most important file from this package is pyproject.toml file which actually is used in orchestrating our project and its dependencies.

[admin@fedwor38 poetryprojects]$ poetry new universityportal
Created package universityportal in universityportal
[admin@fedwor38 poetryprojects]$ tree universityportal/
universityportal/
├── pyproject.toml
├── README.md
├── tests
│   └── __init__.py
└── universityportal
    └── __init__.py
[admin@fedwor38 universityportal]$ cat pyproject.toml
[tool.poetry]
name = "universityportal"
version = "0.1.0"
description = ""
authors = ["novicejava1 <sudhirbhoga@gmail.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

Step3: Add Dependencies

Here we are going to add python flask package as the dependency for our project. For this first we need to change to our project directory and then add this dependency as shown below.
This command will automatically find a suitable version constraint and install the package and sub-dependencies. The –verbose option will show us the output in details with errors if any.

[admin@fedwor38 universityportal]$ poetry add flask --verbose
Creating virtualenv flaskapp-zQBetNSt-py3.11 in /home/admin/.cache/pypoetry/virtualenvs
Using virtualenv: /home/admin/.cache/pypoetry/virtualenvs/universityportal-oRnxPJXD-py3.11

  KeyringLocked

  Failed to unlock the collection!

  at ~/.local/share/pypoetry/venv/lib64/python3.11/site-packages/keyring/backends/SecretService.py:67 in get_preferred_collection
       63│             raise InitError("Failed to create the collection: %s." % e)
       64│         if collection.is_locked():
       65│             collection.unlock()
       66│             if collection.is_locked():  # User dismissed the prompt
    →  67│                 raise KeyringLocked("Failed to unlock the collection!")
       68│         return collection
       69│ 
       70│     def unlock(self, item):
       71│         if hasattr(item, 'unlock'):

A workaround for this issue to run the below before adding any dependencies.

[admin@fedwor38 universityportal]$ export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring
[admin@fedwor38 universityportal]$ poetry add flask --verbose
Using virtualenv: /home/admin/.cache/pypoetry/virtualenvs/universityportal-oRnxPJXD-py3.11
Using version ^2.3.2 for flask

Updating dependencies
Resolving dependencies... (0.2s)

Finding the necessary packages for the current system

Package operations: 7 installs, 0 updates, 0 removals

  • Installing markupsafe (2.1.3)
  • Installing blinker (1.6.2)
  • Installing click (8.1.3)
  • Installing itsdangerous (2.1.2)
  • Installing jinja2 (3.1.2)
  • Installing werkzeug (2.3.4)
  • Installing flask (2.3.2)

Writing lock file

Now if we look at the pyproject.toml file our dependency will be added under the section tool.poetry.dependencies as shown below.

[admin@fedwor38 universityportal]$ cat pyproject.toml 
[tool.poetry]
name = "universityportal"
version = "0.1.0"
description = ""
authors = ["novicejava1 <sudhirbhoga@gmail.com>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
flask = "^2.3.2"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

Step4: Clone Flask Application

[admin@fedwor38 universityportal]$ git clone https://github.com/novicejava1/universityportal.git temp
[admin@fedwor38 universityportal]$ cp -pr temp/* universityportal/
[admin@fedwor38 universityportal]$ rm -rf temp
[admin@fedwor38 universityportal]$ mv universityportal/LICENSE .

Step5: Build Flask Application

In this step we are going to package our application. As you can see with “poetry build” it will create two types of packages for us to distribute. They are .tar.gz and .whl packages.

[admin@fedwor38 universityportal]$ poetry build
Building universityportal (0.1.0)
  - Building sdist
  - Built universityportal-0.1.0.tar.gz
  - Building wheel
  - Built universityportal-0.1.0-py3-none-any.whl

Here is the directory structure after the build. As you can see it has created “dist” directory with the packages present in it.

[admin@fedwor38 universityportal]$ tree .
.
├── dist
│   ├── universityportal-0.1.0-py3-none-any.whl
│   └── universityportal-0.1.0.tar.gz
├── LICENSE
├── poetry.lock
├── pyproject.toml
├── README.md
├── tests
│   └── __init__.py
└── universityportal
    ├── app.py
    ├── __init__.py
    ├── static
    │   ├── signup.css
    │   ├── w3 copy.css
    │   └── w3.css
    └── templates
        ├── index.html
        ├── login.html
        ├── setdata.html
        ├── signup.html
        └── student.html

Step6: Run Flask Application

Now we can try to run our Python Flask appication from within the poetry virtual environment which has all our dependencies installed.

[admin@fedwor38 universityportal]$ poetry run flask --app universityportal/app.py run &
 * Serving Flask app 'universityportal/app.py'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

Step7: Validate Flask Application

We can validate if our application has been launched successfully or not by using the below curl command.

[admin@fedwor38 universityportal]$ curl -I http://127.0.0.1:5000
127.0.0.1 - - [07/Jun/2023 12:32:39] "HEAD / HTTP/1.1" 200 -
HTTP/1.1 200 OK
Server: Werkzeug/2.3.4 Python/3.11.2
Date: Wed, 07 Jun 2023 07:02:39 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1260
Connection: close

Hope you enjoyed reading this article. Thank you..