Type casting
Type Casting¶
env-loader-pro automatically casts environment variable strings to their specified types. This page documents the exact casting rules, edge cases, and behavior.
Overview¶
Environment variables are always strings. Type casting converts these strings to the appropriate Python types based on the types parameter.
Supported Types¶
Integer (int)¶
Casts string to integer using Python's int() constructor:
config = load_env(types={"PORT": int})
# Valid inputs
PORT=8080 # → 8080 (int)
PORT=0 # → 0 (int)
PORT=-100 # → -100 (int)
# Invalid inputs raise EnvLoaderError
PORT=not-a-number # → EnvLoaderError
PORT=12.5 # → EnvLoaderError (use float instead)
Integer Parsing
- Leading/trailing whitespace is stripped
- Uses Python's
int()constructor - Hexadecimal (
0xFF) and octal (0o77) formats are supported - Scientific notation (
1e3) is not supported (use float)
Boolean (bool)¶
Boolean casting supports multiple formats for flexibility:
config = load_env(types={"DEBUG": bool})
# True values (case-insensitive)
DEBUG=true # → True
DEBUG=1 # → True
DEBUG=yes # → True
DEBUG=y # → True
DEBUG=t # → True
# False values (case-insensitive)
DEBUG=false # → False
DEBUG=0 # → False
DEBUG=no # → False
DEBUG=n # → False
DEBUG=f # → False
# Invalid values raise EnvLoaderError
DEBUG=maybe # → EnvLoaderError: Cannot cast 'maybe' to bool
Boolean Best Practices
- Use
true/falsefor clarity - Use
1/0for brevity - Avoid ambiguous values like
yes/noin production
Float (float)¶
Casts string to float using Python's float() constructor:
config = load_env(types={"RATE": float})
# Valid inputs
RATE=3.14 # → 3.14 (float)
RATE=0.5 # → 0.5 (float)
RATE=100 # → 100.0 (float)
RATE=1e-3 # → 0.001 (float, scientific notation)
# Invalid inputs raise EnvLoaderError
RATE=not-a-float # → EnvLoaderError
Float Precision
- Uses Python's
float()constructor - Scientific notation is supported (
1e3,1.5e-2) - Infinity and NaN are supported (
inf,nan)
List (list)¶
List casting supports two formats: JSON arrays and comma-separated values.
JSON Arrays¶
JSON arrays are parsed first if the value starts with [ and ends with ]:
config = load_env(types={"DOMAINS": list, "NUMBERS": list, "MIXED": list})
print(config["DOMAINS"]) # ["a.com", "b.com", "c.com"]
print(config["NUMBERS"]) # [1, 2, 3] (preserves JSON types)
print(config["MIXED"]) # ["a", 1, True, None] (preserves JSON types)
JSON Parsing
- Must be valid JSON syntax
- If JSON parsing fails, falls back to comma-separated
- JSON types are preserved (numbers, booleans, null)
Comma-Separated Values¶
If JSON parsing fails or value doesn't start with [, comma-separated parsing is used:
config = load_env(types={"LIMITS": list, "HOSTS": list, "EMPTY": list})
print(config["LIMITS"]) # ["10", "20", "400"] (strings)
print(config["HOSTS"]) # ["192.168.1.1", "10.0.0.1", "172.16.0.1"]
print(config["EMPTY"]) # [] (empty list)
Comma-Separated Behavior
- Values are always strings (not parsed as numbers)
- Empty values are filtered out
- Leading/trailing whitespace is stripped from each item
Empty Lists¶
config = load_env(types={"EMPTY_JSON": list, "EMPTY_CSV": list, "EMPTY_SPACE": list})
print(config["EMPTY_JSON"]) # [] (empty list)
print(config["EMPTY_CSV"]) # [] (empty list)
print(config["EMPTY_SPACE"]) # [] (empty list)
String (Default)¶
If no type is specified, values remain strings:
Type Casting Examples¶
Complete Example¶
# .env
PORT=8080
DEBUG=true
TIMEOUT=30.5
DOMAINS=["api.example.com","web.example.com"]
ALLOWED_IPS=192.168.1.1,10.0.0.1
RATE=0.05
config = load_env(
types={
"PORT": int,
"DEBUG": bool,
"TIMEOUT": float,
"DOMAINS": list,
"ALLOWED_IPS": list,
"RATE": float
}
)
print(type(config["PORT"])) # <class 'int'>
print(type(config["DEBUG"])) # <class 'bool'>
print(type(config["TIMEOUT"])) # <class 'float'>
print(type(config["DOMAINS"])) # <class 'list'>
print(type(config["ALLOWED_IPS"])) # <class 'list'>
print(type(config["RATE"])) # <class 'float'>
Error Handling¶
Invalid Type Conversion¶
When a value cannot be cast to the specified type, EnvLoaderError is raised:
# .env: PORT=not-a-number
config = load_env(types={"PORT": int})
# Raises: EnvLoaderError: Failed to cast env value 'not-a-number' to int
Invalid Boolean¶
Boolean casting is strict - only specific values are accepted:
# .env: DEBUG=maybe
config = load_env(types={"DEBUG": bool})
# Raises: EnvLoaderError: Cannot cast 'maybe' to bool
Invalid List Format¶
If a list value cannot be parsed:
# .env: DOMAINS=[invalid json
config = load_env(types={"DOMAINS": list})
# Falls back to comma-separated: ["[invalid", "json"]
Type Casting Order¶
Type casting happens after all sources are merged:
- Load from all sources (providers, system, files)
- Merge with precedence
- Expand variables (
${VAR}) - Apply type casting ← Here
- Apply defaults (if not already cast)
- Validate
Casting After Merging
This means type casting sees the final merged value, not individual source values.
Edge Cases¶
Whitespace Handling¶
All values are stripped of leading/trailing whitespace before casting:
config = load_env(types={"PORT": int, "DEBUG": bool})
print(config["PORT"]) # 8080 (whitespace stripped)
print(config["DEBUG"]) # True (whitespace stripped)
Empty Values¶
Empty values behave differently by type:
config = load_env(
types={"EMPTY_STR": str, "EMPTY_INT": int, "EMPTY_BOOL": bool, "EMPTY_LIST": list},
defaults={"EMPTY_STR": "", "EMPTY_INT": 0, "EMPTY_BOOL": False, "EMPTY_LIST": []}
)
# Empty string: remains empty string
# Empty int: raises EnvLoaderError (use default instead)
# Empty bool: raises EnvLoaderError (use default instead)
# Empty list: becomes [] (empty list)
None Values¶
JSON null values are preserved in JSON arrays:
Type Safety with Schemas¶
For better type safety and validation, use schema validation:
from env_loader_pro import load_with_schema
from pydantic import BaseModel
class Config(BaseModel):
port: int
debug: bool
timeout: float
domains: list[str]
config = load_with_schema(Config)
# All types validated and enforced by Pydantic
Schema vs Types
typesparameter: Simple casting, no validation- Schema (Pydantic/dataclass): Type validation + business rules
Best Practices¶
-
Always specify types for non-string values
-
Use schemas for complex configurations
-
Handle casting errors gracefully
-
Use defaults for optional typed values
Related Topics¶
- Validation - Validate values after casting
- Schema Support - Type-safe schemas with validation