question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[QUESTION] How do I pass environment variables to my route files?

See original GitHub issue

From the example given here - https://fastapi.tiangolo.com/tutorial/bigger-applications/

I have this kind of structure.

.
├── app
│   ├── __init__.py
│   ├── main.py
│   └── routers
│       ├── __init__.py
│       ├── items.py
│       └── users.py

I would like to read environment variables, when running/deploying my code, and then pass those variables to items.py and users.py

How do I achieve this?

Do I have to use tags or is that for some other purpose?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

14reactions
dmontagucommented, Jul 24, 2019

@unography I would recommend the use of the BaseSettings class in pydantic. Here’s a basic example:

from functools import lru_cache
import os
from typing import Optional

from pydantic import BaseSettings


class AppSettings(BaseSettings):
    project_name: str = "My API"
    debug: bool = False

    # Server
    server_name: Optional[str]
    server_host: Optional[str]
    sentry_dsn: Optional[str]
    secret_key: bytes = os.urandom(32)

    ...

    class Config:
        env_prefix = ""  # defaults to 'APP_'; see description in pydantic docs
        allow_mutation = False


@lru_cache()
def get_settings() -> AppSettings:
    return AppSettings()

This way you can basically treat the settings like a singleton by only accessing them via get_settings(), with the benefit that you can modify the environment after module imports but prior to the first call to get_settings, and the settings will reflect the environment on its first call. (This may be useful for testing purposes.)

4reactions
fgimiancommented, Oct 6, 2019

I just wanted to add a further approach that you may wish to take. My approach is more similar to Flask and Django; it depends on environment variables mainly for knowing the path of your settings file.

I’ve chosen to use TOML, but you can use YAML or JSON too.

My settings.py file looks like this:

import os
from functools import lru_cache
from typing import Dict, List

import toml
from pydantic import BaseModel


class DatabaseSettings(BaseModel):
    host: str
    port: int
    username: str
    password: str
    db_name: str
    max_connections: int


class JWTSettings(BaseModel):
    key: str
    session_duration: int


class AuthenticationSettings(BaseModel):
    cert_path: str
    hosts: List[str]
    username: str
    password: str
    group_access: Dict[str, List[str]]


class Settings(BaseModel):
    database: DatabaseSettings
    jwt: JWTSettings
    authentication: AuthenticationSettings


@lru_cache()
def get_settings() -> Settings:
    settings_path = os.environ.get("MYAPP_SETTINGS", "/etc/myapp/myapp-app.toml")

    with open(settings_path) as fp:
        settings = Settings.parse_obj(toml.load(fp))

    return settings

It is also easy to point your unit tests to your testing config as long as you don’t attempt to use get_settings too early.

os.environ["MYAPP_SETTINGS"] = "settings/testing/myapp-app.toml"


@pytest.fixture
def client():
    return TestClient(app)

If you are in a situation where this causes you trouble, you may wrap your app in a get_app function which is called similarly to that below in main.py:

if os.path.basename(sys.argv[0]) in ["gunicorn", "uvicorn"]:
    app = get_app()

This way, importing the main module in your unit tests won’t create the app and you are free to set the appropriate environment variable before calling get_app yourself 😄

Note: In case anyone is unaware, it seems impossible to call a function when running gunicorn or uvicorn like you can with sync workers. As such, the main module must define an app variable itself which is why we need that litle trick above.

The best way to avoid this problem is to use the startup event handler for anything that must happen upon startup that needs to access settings. The startup event won’t run immediately when the app is imported in your unit tests; only once the TestClient starts using it;.

Really hope this helps and provides some more ideas which we can develop further together.

Cheers Fotis

Read more comments on GitHub >

github_iconTop Results From Across the Web

Laravel, ENV Variable from routes file - Stack Overflow
The reason is I want to make special routes group for dashboard / client area. Here is my latest code; $dashboard = env('DASHBOARD_DOMAIN',...
Read more >
Working with Environment Variables in Node.js - Twilio
Environment variables are a great way to configure parts of your Node.js application. Learn how to work with them using helpful tools such ......
Read more >
What are PATH and other environment variables, and how ...
To do so, right click on the desktop, select New Shortcut, and enter systempropertiesadvanced.exe. Then you can click on the link to get...
Read more >
Environment variables in Compose | Docker Documentation
You can set default values for environment variables using a .env file, which Compose automatically looks for in project directory (parent folder of...
Read more >
Node.js Everywhere with Environment Variables! - Medium
The following command will preload all environment variables from the file . env using dotenv and make them available in your app. So...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found