Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Setting Environment Variables

00:00 Environment Variables. You’re currently developing your Python URL shortener on your local computer. But once you want to make it available to your users, you may need to deploy it to the web.

00:14 It makes sense to use different settings for different environments. Your local development environment may use a differently named database than an online production environment. To be flexible, you store this information in special variables that you can adjust for each environment. While you won’t take steps to host your app online in this course, you’ll build your app in a way that enables you to deploy easily to the cloud in the future. If you want to learn more about deployment, then check out Python Web Applications: Deploy Your Script as a Flask App or Deploying a Python Flask Example Application Using Heroku.

00:56 Start by creating a config.py file with the default settings.

01:03 First you import pydantic, which was installed automatically when you installed fastapi with pip. pydantic is a library that uses type annotation to validate data and manage settings.

01:17 The Settings class is a subclass of BaseSettings. The BaseSettings class comes in handy to define environment variables in your application.

01:26 You only have to define the variables that you want to use, and pydantic takes care of the rest. In other words, pydantic will automatically assume those default values if it doesn’t find the corresponding environment variables.

01:40 In this case, you’re defining the default settings for env_name, base_url, and db_url. Later you’ll replace their values with external environment variables.

01:54 It’s a good start to have these variables in place with default values, but since the values for your current environment, the domain of your app, and the address of your database are dependent on the environment that you are working in, you’ll load the values from external environment variables later on.

02:12 To show a message once your settings are loaded, you create get_settings(). This function returns an instance of your Settings class and will provide you with the option of caching your settings.

02:30 But before you investigate why you need caching, save the config.py file and run get_settings() in a Python interactive interpreter.

02:47 If you get an error when trying to run the import command, make sure that your Python interpreter was started from within the project’s root directory. The settings are loaded correctly when you call get_settings().

03:04 However, you can optimize the retrieval of your settings a bit more. Your app settings are not changed while running the app, but still you’re loading the settings over and over again every time you call get_settings. You can take advantage of get_settings() being a function to implement a Least Recently Used strategy.

03:26 When you start your app, it makes sense to load your settings and then cache the data. Caching is an optimization technique that you can use in your applications to keep recent or often-used data in memory.

03:40 You can implement an LRU cache strategy to accomplish this behavior. First you import lru_cache from Python’s functools module.

03:55 The @lru_cache decorator wraps the get_settings() function. This allows you to cache the result of get_settings() using the LRU strategy.

04:05 You can see how this works from the Python REPL.

04:23 Now you see the Loading settings message only once. That means that your settings are successfully cached. By adding the @lru_cache decorator, you made your app faster while decreasing the load on computing resources.

04:39 Another improvement that you’ll implement is loading external environment variables. Start by creating an external .env file in the root directory of your project. And then add the content seen on-screen.

05:03 By storing your environment variables externally, you are following the twelve-factor app methodology. The twelve-factor app methodology states twelve principles to enable developers to build portable and scalable web applications.

05:21 One principle is to store the configuration of your app in the environment. This includes resource handles to the database, Memcached, and other backing services; credentials to external services such as Amazon S3 or Twitter; and per-deploy values such as the canonical hostname for the deployment.

05:41 The twelve-factor principles require strict separation of config from code. Config varies substantially across deployments, and code does not. It’s recommended to have different .env files for different environments. Also, you should never add the .env file to your version control system, as your environment, variables may store sensitive information.

06:07 Note that if you’re sharing your code with other developers, then you may want to show in your repository what their .env files should look like. In that case, you can add .env_sample to your version control system.

06:22 In .env_sample, you can store the keys with placeholder values. To help yourself and your fellow developers, don’t forget to write instructions in your README file on how to rename .env_sample and store the correct values in the file.

06:38 The configuration variables that you used in your Settings class are a fallback for your external environment variables. In the .env file, you are declaring the same variables for your development environment.

06:50 When you deploy the application to the web, you declare the environment variables for each environment. To load the external .env file, adjust the Settings class in the config.py file.

07:07 With the addition of the Config class with the path to the env_file, pydantic loads your environment variables from that .env file.

07:19 Test your external environment variables by running the command seen on-screen.

07:34 Now you can see that the variables are the ones that you declared in the .env file. Your app now works with external variables.

07:45 With all of these previous instructions followed, then the directory tree should look as seen on-screen. The url_shortener_project/ directory contains the shortener_app/ folder. In that folder, at the moment, there are two files, a .__init__.py file and a config.py file. In the url_shortener_project/ folder, you’ll also have your virtual environment and the .env file you created in the previous step.

08:14 So now that everything’s in place, in the next section of the course, you’ll start setting up your URL shortener.

Avatar image for mandar-gite

mandar-gite on Sept. 16, 2022

I have tried to cache the settings but getting the following error messageL

(venv) mandar@desk:~/url_project$ python3
Python 3.11.0rc1 (main, Aug  8 2022, 18:31:54) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> get_settings.base_url
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'get_settings' is not defined

The code is:

# shortener_app/config.py

from functools import lru_cache

from pydantic import BaseSettings

class Settings(BaseSettings):
    env_name: str = "Local"
    base_url: str = "http://localhost:8000"
    db_url: str = "sqlite:///./shortner.db"

def get_settings() -> Settings:
    settings = Settings()
    print(f"Loading setting for :{settings.env_name}")
    return settings

What am I doing wrong?

Become a Member to join the conversation.