0
# Environment and Configuration
1
2
System for parsing Procfiles, managing environment variables, and expanding process configurations with concurrency and port assignment. This module handles all aspects of configuration management for Procfile-based applications.
3
4
## Capabilities
5
6
### Environment Management
7
8
The Env class provides configuration management with support for Procfiles, environment variables, and port configuration.
9
10
```python { .api }
11
class Env:
12
"""
13
Environment configuration manager that handles Procfile loading,
14
port configuration, and application root directory management.
15
"""
16
17
def __init__(self, config):
18
"""
19
Initialize environment with configuration dictionary.
20
21
Parameters:
22
- config: dict, configuration mapping (typically from ChainMap)
23
"""
24
25
def load_procfile(self):
26
"""
27
Load and parse the Procfile.
28
29
Returns:
30
Procfile object with parsed processes
31
32
Raises:
33
IOError: if Procfile doesn't exist or isn't readable
34
AssertionError: if Procfile format is invalid
35
"""
36
37
@property
38
def port(self):
39
"""
40
Get port as integer from configuration.
41
42
Returns:
43
int: port number
44
45
Raises:
46
ValueError: if port value is invalid
47
"""
48
49
@property
50
def procfile(self):
51
"""
52
Get full path to Procfile.
53
54
Returns:
55
str: absolute path to Procfile
56
"""
57
```
58
59
### Procfile Management
60
61
Data structures and functions for parsing and managing Procfile content.
62
63
```python { .api }
64
class Procfile:
65
"""
66
Data structure representing a Procfile with process definitions.
67
"""
68
69
def __init__(self):
70
"""Initialize empty Procfile."""
71
72
def add_process(self, name, command):
73
"""
74
Add a process to the Procfile.
75
76
Parameters:
77
- name: str, process name (must be unique)
78
- command: str, command to execute
79
80
Raises:
81
AssertionError: if process name is not unique
82
"""
83
84
# Properties
85
processes: 'OrderedDict[str, str]' # Mapping of process names to commands
86
```
87
88
```python { .api }
89
def parse_procfile(contents):
90
"""
91
Parse Procfile content into a Procfile object.
92
93
Parameters:
94
- contents: str, raw Procfile content
95
96
Returns:
97
Procfile object with parsed processes
98
"""
99
```
100
101
### Environment Variable Parsing
102
103
Functions for parsing .env files and environment variable configuration.
104
105
```python { .api }
106
def parse(content):
107
"""
108
Parse the content of a .env file (KEY=value format) into a dictionary.
109
110
Parameters:
111
- content: str, .env file content with KEY=value lines
112
113
Returns:
114
dict: mapping of environment variable names to values
115
"""
116
```
117
118
### Process Expansion
119
120
Functions for expanding process definitions with concurrency, environment variables, and port assignment.
121
122
```python { .api }
123
def expand_processes(processes, concurrency=None, env=None, quiet=None, port=None):
124
"""
125
Get a list of processes that need to be started given the specified
126
process types, concurrency, environment, quietness, and base port number.
127
128
Parameters:
129
- processes: dict, mapping of process names to commands
130
- concurrency: dict, optional concurrency specification per process type
131
- env: dict, optional environment variables to apply to all processes
132
- quiet: list, optional list of process names to suppress output for
133
- port: int, optional base port number for PORT environment variable
134
135
Returns:
136
List[ProcessParams]: list of process parameter objects with name, cmd, env, and quiet
137
"""
138
139
ProcessParams = namedtuple("ProcessParams", "name cmd quiet env")
140
```
141
142
## Usage Examples
143
144
### Basic Procfile Parsing
145
146
```python
147
from honcho.environ import parse_procfile, Env
148
149
# Parse Procfile content
150
procfile_content = """
151
web: python app.py
152
worker: python worker.py
153
scheduler: python scheduler.py
154
"""
155
156
procfile = parse_procfile(procfile_content)
157
print(procfile.processes)
158
# OrderedDict([('web', 'python app.py'), ('worker', 'python worker.py'), ('scheduler', 'python scheduler.py')])
159
```
160
161
### Environment Configuration
162
163
```python
164
from honcho.environ import Env
165
166
# Configuration typically comes from command-line args, env vars, and defaults
167
config = {
168
'app_root': '/path/to/app',
169
'procfile': 'Procfile',
170
'port': '5000'
171
}
172
173
env = Env(config)
174
175
# Load Procfile
176
try:
177
procfile = env.load_procfile()
178
print(f"Found {len(procfile.processes)} processes")
179
except IOError:
180
print("Procfile not found")
181
182
# Get port configuration
183
try:
184
port = env.port
185
print(f"Port: {port}")
186
except ValueError as e:
187
print(f"Invalid port: {e}")
188
```
189
190
### Environment Variable Parsing
191
192
```python
193
from honcho.environ import parse
194
195
# Parse .env file content
196
env_content = """
197
DATABASE_URL=postgresql://localhost:5432/mydb
198
DEBUG=true
199
SECRET_KEY=my-secret-key
200
PORT=8000
201
"""
202
203
env_vars = parse(env_content)
204
print(env_vars)
205
# {'DATABASE_URL': 'postgresql://localhost:5432/mydb', 'DEBUG': 'true', 'SECRET_KEY': 'my-secret-key', 'PORT': '8000'}
206
```
207
208
### Process Expansion with Concurrency
209
210
```python
211
from honcho.environ import expand_processes, parse_procfile
212
213
# Parse Procfile
214
procfile_content = """
215
web: python app.py
216
worker: python worker.py
217
"""
218
procfile = parse_procfile(procfile_content)
219
220
# Expand processes with concurrency and port assignment
221
concurrency = {'web': 2, 'worker': 3}
222
env_vars = {'DATABASE_URL': 'postgresql://localhost:5432/mydb'}
223
base_port = 5000
224
225
expanded = expand_processes(
226
procfile.processes,
227
concurrency=concurrency,
228
env=env_vars,
229
port=base_port
230
)
231
232
for process in expanded:
233
print(f"Name: {process.name}")
234
print(f"Command: {process.cmd}")
235
print(f"Environment: {process.env}")
236
print(f"Quiet: {process.quiet}")
237
print("---")
238
239
# Output:
240
# Name: web.1
241
# Command: python app.py
242
# Environment: {'DATABASE_URL': 'postgresql://localhost:5432/mydb', 'HONCHO_PROCESS_NAME': 'web.1', 'PORT': '5000'}
243
# Quiet: False
244
# ---
245
# Name: web.2
246
# Command: python app.py
247
# Environment: {'DATABASE_URL': 'postgresql://localhost:5432/mydb', 'HONCHO_PROCESS_NAME': 'web.2', 'PORT': '5001'}
248
# Quiet: False
249
# ---
250
# Name: worker.1, worker.2, worker.3...
251
```
252
253
### Configuration Chaining
254
255
```python
256
from collections import ChainMap
257
import os
258
from honcho.environ import Env
259
260
# Typical configuration chaining from CLI args, env files, OS env, and defaults
261
defaults = {'port': '5000', 'procfile': 'Procfile'}
262
os_env = {'PORT': os.environ.get('PORT')}
263
env_file = {'DATABASE_URL': 'postgresql://localhost:5432/mydb'}
264
cli_args = {'app_root': '/path/to/app'}
265
266
# Create configuration chain (first match wins)
267
config = ChainMap(cli_args, env_file, os_env, defaults)
268
269
# Create environment manager
270
env = Env(config)
271
```
272
273
## Constants and Patterns
274
275
```python { .api }
276
import re
277
278
# Procfile line pattern for parsing
279
PROCFILE_LINE = re.compile(r'^([A-Za-z0-9_-]+):\s*(.+)$')
280
```