0
# Configuration Management
1
2
PyStow provides a flexible configuration system that supports environment variables and INI files for storing API keys, URLs, connection strings, and other application settings. The configuration system follows a hierarchical lookup strategy.
3
4
## Configuration Functions
5
6
### Reading Configuration
7
8
```python { .api }
9
def get_config(module: str, key: str, *, passthrough: X | None = None, default: X | None = None, dtype: type[X] | None = None, raise_on_missing: bool = False) -> Any:
10
"""Get a configuration value.
11
12
Args:
13
module: Name of the module (e.g., pybel) to get configuration for
14
key: Name of the key (e.g., connection)
15
passthrough: If this is not none, will get returned
16
default: If the environment and configuration files don't contain anything,
17
this is returned.
18
dtype: The datatype to parse out. Can either be int, float,
19
bool, or str. If none, defaults to str.
20
raise_on_missing: If true, will raise a value error if no data is found and
21
no default is given
22
23
Returns:
24
The config value or the default.
25
26
Raises:
27
ConfigError: If raise_on_missing conditions are met
28
"""
29
```
30
31
### Writing Configuration
32
33
```python { .api }
34
def write_config(module: str, key: str, value: str) -> None:
35
"""Write a configuration value.
36
37
Args:
38
module: The name of the app (e.g., indra)
39
key: The key of the configuration in the app
40
value: The value of the configuration in the app
41
"""
42
```
43
44
## Configuration Exceptions
45
46
```python { .api }
47
class ConfigError(ValueError):
48
"""Raised when configuration can not be looked up."""
49
50
def __init__(self, module: str, key: str):
51
"""Initialize the configuration error.
52
53
Args:
54
module: Name of the module, e.g., bioportal
55
key: Name of the key inside the module, e.g., api_key
56
"""
57
```
58
59
## Configuration Hierarchy
60
61
PyStow uses a multi-level configuration lookup system:
62
63
1. **Passthrough values** (if provided directly)
64
2. **Environment variables** (`MODULE_KEY` format, uppercase)
65
3. **INI configuration files** (multiple locations searched)
66
4. **Default values** (if provided)
67
68
### Environment Variable Format
69
70
Environment variables follow the pattern: `{MODULE}_{KEY}` (uppercase)
71
72
Examples:
73
- Module: `myapp`, Key: `api_key` → Environment variable: `MYAPP_API_KEY`
74
- Module: `database`, Key: `host` → Environment variable: `DATABASE_HOST`
75
76
### INI File Locations
77
78
PyStow searches for configuration files in the following order:
79
80
1. `~/.config/config.cfg`
81
2. `~/.config/config.ini`
82
3. `~/.config/pystow.cfg`
83
4. `~/.config/pystow.ini`
84
5. `~/.config/{module}.cfg`
85
6. `~/.config/{module}.ini`
86
7. `~/.config/{module}/{module}.cfg`
87
8. `~/.config/{module}/{module}.ini`
88
9. `~/.config/{module}/conf.ini`
89
10. `~/.config/{module}/config.ini`
90
11. `~/.config/{module}/conf.cfg`
91
12. `~/.config/{module}/config.cfg`
92
93
### INI File Format
94
95
Configuration files use standard INI format:
96
97
```ini
98
[myapp]
99
api_key = your_api_key_here
100
base_url = https://api.example.com
101
timeout = 30
102
debug = true
103
104
[database]
105
host = localhost
106
port = 5432
107
name = myapp_db
108
```
109
110
## Usage Examples
111
112
### Basic Configuration Usage
113
114
```python
115
import pystow
116
117
# Get API key with default
118
api_key = pystow.get_config(
119
"myapp", "api_key",
120
default="default_key"
121
)
122
123
# Get configuration with type conversion
124
timeout = pystow.get_config(
125
"myapp", "timeout",
126
dtype=int,
127
default=30
128
)
129
130
# Get boolean configuration
131
debug_mode = pystow.get_config(
132
"myapp", "debug",
133
dtype=bool,
134
default=False
135
)
136
```
137
138
### Setting Configuration
139
140
```python
141
import pystow
142
143
# Write configuration values
144
pystow.write_config("myapp", "api_key", "your_secret_key")
145
pystow.write_config("myapp", "base_url", "https://api.example.com")
146
pystow.write_config("myapp", "timeout", "60")
147
```
148
149
### Error Handling
150
151
```python
152
import pystow
153
from pystow import ConfigError
154
155
try:
156
# Require configuration value (no default)
157
api_key = pystow.get_config(
158
"myapp", "api_key",
159
raise_on_missing=True
160
)
161
except ConfigError as e:
162
print(f"Configuration missing: {e}")
163
# ConfigError provides helpful setup instructions
164
```
165
166
### Type Conversion
167
168
```python
169
import pystow
170
171
# String values (default)
172
username = pystow.get_config("database", "username")
173
174
# Integer values
175
port = pystow.get_config("database", "port", dtype=int, default=5432)
176
177
# Float values
178
timeout = pystow.get_config("api", "timeout", dtype=float, default=30.0)
179
180
# Boolean values
181
ssl_enabled = pystow.get_config("database", "ssl", dtype=bool, default=True)
182
```
183
184
### Environment Variable Configuration
185
186
```bash
187
# Set environment variables
188
export MYAPP_API_KEY="secret_key_123"
189
export MYAPP_BASE_URL="https://api.example.com"
190
export MYAPP_TIMEOUT="60"
191
export MYAPP_DEBUG="true"
192
```
193
194
```python
195
import pystow
196
197
# These will read from environment variables
198
api_key = pystow.get_config("myapp", "api_key") # "secret_key_123"
199
base_url = pystow.get_config("myapp", "base_url") # "https://api.example.com"
200
timeout = pystow.get_config("myapp", "timeout", dtype=int) # 60
201
debug = pystow.get_config("myapp", "debug", dtype=bool) # True
202
```
203
204
### Configuration File Setup
205
206
Create `~/.config/myapp.ini`:
207
208
```ini
209
[myapp]
210
api_key = your_api_key_here
211
base_url = https://api.example.com/v1
212
timeout = 30
213
debug = false
214
max_retries = 3
215
216
[database]
217
host = db.example.com
218
port = 5432
219
name = production_db
220
ssl = true
221
```
222
223
```python
224
import pystow
225
226
# Read from configuration file
227
api_key = pystow.get_config("myapp", "api_key")
228
db_host = pystow.get_config("database", "host")
229
db_port = pystow.get_config("database", "port", dtype=int)
230
ssl_enabled = pystow.get_config("database", "ssl", dtype=bool)
231
```
232
233
### Advanced Configuration Patterns
234
235
```python
236
import pystow
237
238
class DatabaseConfig:
239
"""Database configuration manager"""
240
241
def __init__(self, module_name="database"):
242
self.module = module_name
243
244
@property
245
def host(self):
246
return pystow.get_config(self.module, "host", default="localhost")
247
248
@property
249
def port(self):
250
return pystow.get_config(self.module, "port", dtype=int, default=5432)
251
252
@property
253
def name(self):
254
return pystow.get_config(self.module, "name", raise_on_missing=True)
255
256
@property
257
def connection_string(self):
258
return f"postgresql://{self.host}:{self.port}/{self.name}"
259
260
# Usage
261
db_config = DatabaseConfig()
262
conn_str = db_config.connection_string
263
```
264
265
### Multi-Environment Configuration
266
267
```python
268
import pystow
269
import os
270
271
# Get environment (development, staging, production)
272
env = os.getenv("ENVIRONMENT", "development")
273
274
def get_env_config(key, **kwargs):
275
"""Get configuration with environment prefix"""
276
return pystow.get_config(f"myapp_{env}", key, **kwargs)
277
278
# Environment-specific configuration
279
api_url = get_env_config("api_url", default="http://localhost:8000")
280
db_host = get_env_config("db_host", default="localhost")
281
debug_mode = get_env_config("debug", dtype=bool, default=True)
282
```
283
284
### Configuration-Driven Downloads
285
286
```python
287
import pystow
288
289
def download_configured_dataset(dataset_name):
290
"""Download dataset using configured URLs"""
291
292
# Get base URL from configuration
293
base_url = pystow.get_config(
294
"datasets", "base_url",
295
default="https://data.example.com"
296
)
297
298
# Get API key if required
299
api_key = pystow.get_config("datasets", "api_key", default=None)
300
301
# Build download URL
302
url = f"{base_url}/datasets/{dataset_name}.csv"
303
304
# Configure download parameters
305
download_kwargs = {}
306
if api_key:
307
download_kwargs["headers"] = {"Authorization": f"Bearer {api_key}"}
308
309
# Download with configuration
310
return pystow.ensure(
311
"myapp", "datasets",
312
url=url,
313
name=f"{dataset_name}.csv",
314
download_kwargs=download_kwargs
315
)
316
317
# Usage
318
dataset_path = download_configured_dataset("training_data")
319
```
320
321
### Configuration Management Utilities
322
323
```python
324
import pystow
325
326
def setup_app_config():
327
"""Interactive configuration setup"""
328
329
print("Setting up MyApp configuration...")
330
331
# Get configuration values interactively
332
api_key = input("Enter API key: ")
333
base_url = input("Enter base URL [https://api.example.com]: ") or "https://api.example.com"
334
timeout = input("Enter timeout in seconds [30]: ") or "30"
335
336
# Write configuration
337
pystow.write_config("myapp", "api_key", api_key)
338
pystow.write_config("myapp", "base_url", base_url)
339
pystow.write_config("myapp", "timeout", timeout)
340
341
print("Configuration saved!")
342
343
def validate_config():
344
"""Validate required configuration exists"""
345
346
required_configs = [
347
("myapp", "api_key"),
348
("myapp", "base_url"),
349
]
350
351
missing = []
352
for module, key in required_configs:
353
try:
354
pystow.get_config(module, key, raise_on_missing=True)
355
except pystow.ConfigError:
356
missing.append(f"{module}.{key}")
357
358
if missing:
359
print(f"Missing required configuration: {', '.join(missing)}")
360
return False
361
362
print("All required configuration present")
363
return True
364
365
# Usage
366
if not validate_config():
367
setup_app_config()
368
```