Python SDK for not-env that transparently overrides os.environ
Project description
not-env-sdk-python
not-env-sdk-python is a Python SDK that fetches environment variables from not-env and transparently overrides os.environ so existing code using os.environ['FOO'] or os.getenv('FOO') works unchanged.
Overview
The SDK:
- Fetches all variables from not-env at startup
- Monkey-patches
os.environto return not-env values - Preserves
NOT_ENV_URLandNOT_ENV_API_KEYfrom OS environment - Makes other keys raise
KeyErrorif not in not-env (hermetic behavior) - Works transparently with existing code
Installation
pip install not-env-sdk
Or with poetry:
poetry add not-env-sdk
Prerequisites
- Python 3.8 or later
- A running not-env backend
- An ENV_READ_ONLY or ENV_ADMIN API key
Quick Start
1. Set Environment Variables
Set the backend URL and API key as OS environment variables:
export NOT_ENV_URL="https://not-env.example.com"
export NOT_ENV_API_KEY="your-env-read-only-key-here"
2. Import the SDK
Import the SDK at the very beginning of your application (before any other code that uses os.environ):
# main.py
import not_env_sdk.register
# Now os.environ is patched
print(os.environ['DB_HOST']) # comes from not-env
print(os.environ['DB_PASSWORD']) # comes from not-env
Or using the direct import:
# main.py
from not_env_sdk import initialize
initialize()
print(os.environ['DB_HOST'])
3. Run Your Application
python main.py
Expected output:
localhost
secret123
If this works correctly, you should see:
- Variable values from not-env printed
- Your application can now use
os.environas usual
Usage Examples
Basic Usage
# app.py
import not_env_sdk.register
import os
db_host = os.environ['DB_HOST']
db_port = os.environ['DB_PORT']
print(f"Connecting to {db_host}:{db_port}")
Using os.getenv()
The SDK also works with os.getenv():
# app.py
import not_env_sdk.register
import os
db_host = os.getenv('DB_HOST')
db_port = os.getenv('DB_PORT', '5432') # with default
print(f"Connecting to {db_host}:{db_port}")
Programmatic Initialization
You can also initialize the SDK programmatically:
# app.py
from not_env_sdk import initialize
initialize(
url="https://not-env.example.com",
api_key="your-key-here"
)
import os
print(os.environ['DB_HOST'])
With Django
For Django applications, import in your settings.py:
# settings.py
import not_env_sdk.register
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
'PORT': os.environ['DB_PORT'],
}
}
With Flask
For Flask applications, import at the top of your application file:
# app.py
import not_env_sdk.register
import os
from flask import Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ['SECRET_KEY']
app.config['DATABASE_URL'] = os.environ['DATABASE_URL']
How It Works
- On Import: The SDK immediately:
- Reads
NOT_ENV_URLandNOT_ENV_API_KEYfromos.environ - Fetches all variables from the
/variablesendpoint - Replaces
os.environwith a custom dict-like object
- Reads
- os.environ Behavior:
NOT_ENV_URLandNOT_ENV_API_KEY: Returned from original OS environment- Other keys: Returned from not-env if they exist, otherwise raise
KeyError - Setting variables: Prevented (hermetic behavior)
- Transparent Integration: Existing code using
os.environ['FOO']oros.getenv('FOO')works without changes.
Environment Variables
Required
NOT_ENV_URL: Backend URL (e.g.,https://not-env.example.com)NOT_ENV_API_KEY: ENV_READ_ONLY or ENV_ADMIN API key
Example
export NOT_ENV_URL="https://not-env.example.com"
export NOT_ENV_API_KEY="dGVzdF9lbnZfcmVhZG9ubHlfa2V5X2hlcmU..."
Example Application
Create a simple example:
# example.py
import not_env_sdk.register
import os
print("Database Configuration:")
print(f" Host: {os.environ['DB_HOST']}")
print(f" Port: {os.environ['DB_PORT']}")
print(f" Name: {os.environ['DB_NAME']}")
# Use variables as normal
connection_string = f"postgresql://{os.environ['DB_USER']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ['DB_PORT']}/{os.environ['DB_NAME']}"
print(f"Connection: {connection_string}")
Run it:
NOT_ENV_URL="https://not-env.example.com" \
NOT_ENV_API_KEY="your-key" \
python example.py
Expected output:
Database Configuration:
Host: localhost
Port: 5432
Name: myapp
Connection: postgresql://user:pass@localhost:5432/myapp
If this works correctly, you should see:
- All variables printed from not-env
- Connection string built using those variables
- No errors or KeyError exceptions (assuming variables exist in not-env)
Error Handling
Missing Environment Variables
If NOT_ENV_URL or NOT_ENV_API_KEY are missing:
ValueError: NOT_ENV_URL environment variable is required
Solution: Set both environment variables before running your application.
Backend Unreachable
If the backend is unreachable:
RuntimeError: Request failed: getaddrinfo ENOTFOUND not-env.example.com
Solution: Check the NOT_ENV_URL and ensure the backend is running and accessible.
Invalid API Key
If the API key is invalid:
RuntimeError: Failed to fetch variables: 401 - Unauthorized
Solution: Verify your NOT_ENV_API_KEY is correct and not revoked.
Initialization Failure
If initialization fails, the SDK will:
- Print an error to stderr
- Exit the process with code 1
This ensures your application doesn't run with incorrect configuration.
Behavior Details
Hermetic Behavior
The SDK provides hermetic behavior:
- Variables not in not-env raise
KeyErrorwhen accessed viaos.environ['KEY'] - Variables not in not-env return
None(or default) when accessed viaos.getenv('KEY') - No fallback to OS environment variables (except
NOT_ENV_URLandNOT_ENV_API_KEY) - Prevents setting variables at runtime
Preserved Variables
These variables are always preserved from OS environment:
NOT_ENV_URLNOT_ENV_API_KEY
Variable Access
os.environ['KEY']: Returns value from not-env if exists, otherwise raisesKeyErroros.getenv('KEY'): Returns value from not-env if exists, otherwise returnsNoneos.getenv('KEY', default): Returns value from not-env if exists, otherwise returnsdefaultos.environ['KEY'] = value: Prevented (raisesRuntimeError)'KEY' in os.environ: ReturnsTrueonly if key exists in not-env (or preserved vars)list(os.environ.keys()): Returns only keys from not-env (plus preserved vars)
Compatibility
Supported Runtimes
- Python 3.8+
- Django
- Flask
- FastAPI
- Any Python application
Not Supported
- Python 2.x (end of life)
- Python 3.7 and earlier
Integration with CLI
The SDK works alongside the CLI:
- CLI: Use
not-env env setto load variables into your shell - SDK: Use
import not_env_sdk.registerto load variables in Python
Both can be used together - CLI for shell scripts, SDK for Python applications.
Troubleshooting
Variables raise KeyError
- Check that variables exist in not-env:
not-env var list - Verify you're using the correct API key (ENV_READ_ONLY or ENV_ADMIN)
- Ensure the SDK is imported before any code that uses
os.environ - Use
os.getenv('KEY')instead ofos.environ['KEY']if you wantNoneinstead ofKeyError
SDK not loading
- Ensure the SDK is imported at the very top of your entry file
- Check that
NOT_ENV_URLandNOT_ENV_API_KEYare set - Verify the backend is accessible
Performance concerns
- Variables are fetched once at startup
- No caching beyond the initial fetch
- Network request happens synchronously during import
Security Notes
- API Keys: Store
NOT_ENV_API_KEYsecurely. Never commit it to version control. - HTTPS: Always use HTTPS for
NOT_ENV_URLin production. - Read-Only Keys: Use ENV_READ_ONLY keys when possible for better security.
Next Steps
- Set up your backend
- Use the CLI to manage variables
- Integrate the SDK into your Python applications
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file not_env_sdk-0.1.0.tar.gz.
File metadata
- Download URL: not_env_sdk-0.1.0.tar.gz
- Upload date:
- Size: 12.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d46ef0a99bda983bf9da55c9435b984ac7949f5584f1e3bc44ab5e9a0a6c6b9f
|
|
| MD5 |
7142789d4d2ad1155c8b58aaa9935700
|
|
| BLAKE2b-256 |
d8b34207fd82dea75c3dbce13ec783b2017395b53ca09a169c686ea2fc2f50fb
|
File details
Details for the file not_env_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: not_env_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
529186b547ba60e173910ade31dbc18db0f45ebf65037d5e0a392d53e262cb07
|
|
| MD5 |
f718fb1761da60c2311d06798e572400
|
|
| BLAKE2b-256 |
6425822d43e7055beb0fc23001ede96a8f6361d6228a950622989e3cb079c398
|