Flask is the most used framework for web development according to the Jetbrains Python Developers Survey from 2020, and in May of 2021, version
2.0.0
of Flask came out with 31 new changes.
In this post, you'll learn about some of those changes and the refactoring you might want to do to your code to take the most advantage of this new version.What's New?
At the beginning of this post, I mentioned 31 alterations were added to this release of the framework, and you can read about all of them here.
First and foremost, the most critical change on Flask
2.0.0
is that Flask officially dropped support for Python 2 and 3.5. If you are using these versions on your projects and want to update to Flask 2.0.0
, you need to also update the Python version you are using.“Flask officially drops support for Python 2 and 3.5! Time to update the Python version in your projects!”
Tweet This
But let focus on the 3 things that I personally like the most:
- Type hinting is here!
- You can read the application configuration from any file.
- My favorite syntactic sugar just arrived: HTTP method-specific decorators for defining routes.
How To Upgrade
Let's start at the beginning: Upgrading Flask's version. For running an app locally, just remember to activate your Python environment (if you use one) and run the following:
pip install -U Flask==2.0.0
The
-U
flag tells pip
to upgrade the version of Flask on your environment to version 2.0.0
. After that, it is time to update the codebase. If your codebase uses unit or integration tests, it is a great time to see if any of them break and to fix the code accordingly. 😉After doing the upgrade, you might want to also update your environment files like
requirements.txt
and Pipenv
.Type Hinting
As The Zen of Python states: Explicit is better than implicit, and type hinting is a beautiful way of explicitly telling anyone reading a class or function documentation what that object expects as a parameter. Now, all of Flask has typing annotations.
Consider this: it has been a while since you used Flask, and you don't quite remember what a given parameter receives. You might not even remember what type of object that parameter receives. You might try to find the examples for the class you want to use, or now you can simply check the class signature by using the help function, and it will clearly state what that parameter receives.
Let's see a more concrete example. Let's check out the help for the Flask class, but let's see how it was before first.
Here I have an environment with Flask on version
1.1.4
(the last version before 2.0.0
), and when I open up the python
console and import the Flask
class and then call the help()
function to display the class documentation:from flask import Flask help(Flask)
This is what you'll see:
Now, if you do the same thing in a Python environment with Flask
2.0.0
, this is what you'll see:If you look closely, you can see that
instance_relative_config
should receive a boolean value instead of assuming it would be boolean because the default for that parameter is False
.This isn't a change that prompts you to update your code, but it will come in handy when you start writing new endpoints or adding more functionality to the ones already there.
Reading The Configuration From Any File
Depending on size, objective, or even personal taste, you might like to load the configurations for your application from a file.
So you might already read your configuration from a JSON file, but guess what?! Now you can read the configuration from any type of file as long as a file reader can understand those files. So if you were longing to have TOML files holding your configuration information, rejoice! Now you can! 🎉
Let's take a closer look and see how that works. Let's say you have the following TOML to hold your configuration and that you already have the
package installed on your environment:toml
# config.toml DEBUG = true SECRET_KEY = "development key"
Now all you have to do is use the new
.from_file()
method to read the variables from the configuration file. This is done by passing the file path and the file reader to the .from_file()
method:import toml from flask import Flask app = Flask('__name__') app.config.from_file('config.toml', toml.load)
Also, if you were using the
.from_json()
to load your configs, that has been deprecated! You'll need to update your code to use the .from_file()
method. You probably had something like this before:from flask import Flask app = Flask('__name__') app.config.from_json('config.json')
Here's the updated version using the
.from_file()
method:import json from flask import Flask app = Flask('__name__') app.config.from_file('config.json', json.load)
The most important thing to keep in mind when using
.from_file()
is that you have to have a function that parses that type of file, which means you might need to import new modules or libraries for reading and parsing that file. In the example above, I used the json
module to read the configuration from a JSON file, whereas to read from a TOML file, I had to install the toml
package.With those changes, you should be good to go. 😉
New HTTP Method Specific Decorators
Finally, my favorite change: HTTP method-specific decorators! If you've been doing RESTful APIs using Flask, you are probably accustomed to doing something like the following code snippet:
from flask import Flask app = Flask('__name__') @app.route('/first', methods=['GET']) def my_get_endpoint(): return 'This was a GET request.' @app.route('/second', methods=['POST']) def my_post_endpoint(): return 'This was a POST request.' @app.route('/third', methods=['PUT']) def my_put_endpoint(): return 'This was a PUT request.'
This Flask version provides syntactic sugar that allows you to register routes for the most common HTTP methods (
GET
, POST
, PUT
, DELETE
, and PATCH
) in a more direct way like other frameworks such as FastAPI are doing. If you want to use this, you just have to change your traditional @app.route
for a @app.<method>
. Here is a refactored version of the above example:from flask import Flask app = Flask('__name__') @app.get('/first') def my_get_endpoint(): return 'This was a GET request.' @app.post('/second') def my_post_endpoint(): return 'This was a POST request.' @app.put('/third') def my_put_endpoint(): return 'This was a PUT request.'
This isn't a mandatory change. You can still use the traditional
@app.route
method to register your endpoints, but know that the syntactic sugar is available to you now.Wrapping Up
There were many changes made in this release of Flask, and I only covered a few of them in this blog post. What were your favorite changes, and why? Are you planning on upgrading to the newest version of Flask? Leave your comments and questions on the community forum. 😉
Also, the code I showed here is available in this repository on GitHub.