0
# Application Foundation
1
2
The foundation system provides the core application framework classes that serve as the entry point and container for all cement-based applications. The `App` class manages the complete application lifecycle, while `TestApp` provides specialized functionality for testing.
3
4
## Capabilities
5
6
### App Class
7
8
The main application framework class that serves as the central container for all application components and functionality.
9
10
```python { .api }
11
class App:
12
"""
13
Main application class that handles the entire application lifecycle.
14
15
The App class manages setup, execution, and cleanup of cement applications.
16
It serves as the central container for all handlers, interfaces, extensions,
17
and configuration management.
18
"""
19
20
def __init__(self, label: str = None, **kw: Any) -> None:
21
"""
22
Initialize the application.
23
24
Args:
25
label: Application label/name
26
**kw: Additional keyword arguments passed to Meta
27
"""
28
29
def setup(self) -> None:
30
"""
31
Initialize and setup the application for execution.
32
33
This method handles:
34
- Loading configuration files
35
- Setting up logging
36
- Loading extensions and plugins
37
- Registering handlers
38
- Running pre_setup and post_setup hooks
39
"""
40
41
def run(self) -> None:
42
"""
43
Execute the application.
44
45
This method handles:
46
- Parsing command-line arguments
47
- Running pre_run hooks
48
- Executing the appropriate controller/command
49
- Running post_run hooks
50
- Exception handling and signal management
51
"""
52
53
def close(self) -> None:
54
"""
55
Cleanup and shutdown the application.
56
57
This method handles:
58
- Running pre_close and post_close hooks
59
- Cleaning up resources
60
- Proper application shutdown
61
"""
62
63
def render(self, data: Dict[str, Any], template: str = None) -> str:
64
"""
65
Render data using the configured output handler.
66
67
Args:
68
data: Dictionary of data to render
69
template: Optional template name for template-based output
70
71
Returns:
72
Rendered output string
73
"""
74
75
def extend(self, extension: str, app: 'App') -> None:
76
"""
77
Register a framework extension.
78
79
Args:
80
extension: Extension name/identifier
81
app: Application instance to extend
82
"""
83
84
@property
85
def _meta(self) -> Any:
86
"""Application meta-data configuration object."""
87
```
88
89
### TestApp Class
90
91
Specialized application class designed for unit testing cement applications with additional testing utilities and simplified configuration options.
92
93
```python { .api }
94
class TestApp(App):
95
"""
96
Application class designed specifically for testing cement applications.
97
98
Inherits all functionality from App but provides additional testing
99
conveniences and simplified configuration for test environments.
100
"""
101
102
def __init__(self, label: str = None, **kw: Any) -> None:
103
"""
104
Initialize the test application.
105
106
Args:
107
label: Application label/name
108
**kw: Additional keyword arguments passed to Meta
109
"""
110
```
111
112
### Meta Configuration
113
114
Application behavior is controlled through the Meta class which can be defined as a nested class or passed as keyword arguments during initialization.
115
116
```python { .api }
117
class Meta:
118
"""
119
Application meta-data configuration.
120
121
Controls application behavior including handler selection,
122
configuration options, and framework settings.
123
"""
124
125
label: str = None
126
"""Application label/name"""
127
128
debug: bool = False
129
"""Debug mode flag"""
130
131
config_handler: str = 'configparser'
132
"""Configuration handler to use"""
133
134
config_file_suffix: str = '.conf'
135
"""Configuration file suffix"""
136
137
config_files: List[str] = []
138
"""List of configuration files to load"""
139
140
config_dirs: List[str] = []
141
"""List of configuration directories to search"""
142
143
config_defaults: Dict[str, Any] = {}
144
"""Default configuration values"""
145
146
argv: List[str] = None
147
"""Override sys.argv for argument parsing"""
148
149
catch_signals: List[int] = [signal.SIGTERM, signal.SIGINT]
150
"""List of signals to catch and handle"""
151
152
signal_handler: str = 'signal'
153
"""Signal handler to use"""
154
155
pre_setup_hooks: List[Callable] = []
156
"""List of pre-setup hook functions"""
157
158
post_setup_hooks: List[Callable] = []
159
"""List of post-setup hook functions"""
160
161
pre_run_hooks: List[Callable] = []
162
"""List of pre-run hook functions"""
163
164
post_run_hooks: List[Callable] = []
165
"""List of post-run hook functions"""
166
167
pre_close_hooks: List[Callable] = []
168
"""List of pre-close hook functions"""
169
170
post_close_hooks: List[Callable] = []
171
"""List of post-close hook functions"""
172
173
handlers: List[Handler] = []
174
"""List of handler classes to register"""
175
176
extensions: List[str] = []
177
"""List of extensions to load"""
178
179
plugins: List[str] = []
180
"""List of plugins to load"""
181
182
plugin_config_dirs: List[str] = []
183
"""List of plugin configuration directories"""
184
185
plugin_dirs: List[str] = []
186
"""List of plugin directories to search"""
187
188
template_handler: str = 'dummy'
189
"""Template handler to use"""
190
191
template_dirs: List[str] = []
192
"""List of template directories"""
193
194
output_handler: str = 'dummy'
195
"""Output handler to use"""
196
197
log_handler: str = 'logging'
198
"""Log handler to use"""
199
200
cache_handler: str = 'dummy'
201
"""Cache handler to use"""
202
203
mail_handler: str = 'dummy'
204
"""Mail handler to use"""
205
206
argument_handler: str = 'argparse'
207
"""Argument handler to use"""
208
209
base_controller: str = None
210
"""Base controller class name"""
211
```
212
213
## Usage Examples
214
215
### Basic Application
216
217
```python
218
from cement import App, Controller, ex
219
220
class BaseController(Controller):
221
class Meta:
222
label = 'base'
223
224
@ex(help='say hello')
225
def hello(self):
226
print('Hello World!')
227
228
class MyApp(App):
229
class Meta:
230
label = 'myapp'
231
base_controller = 'base'
232
handlers = [BaseController]
233
234
def main():
235
with MyApp() as app:
236
app.run()
237
238
if __name__ == '__main__':
239
main()
240
```
241
242
### Application with Configuration
243
244
```python
245
from cement import App, init_defaults
246
247
CONFIG = init_defaults('myapp')
248
CONFIG['myapp']['debug'] = False
249
CONFIG['myapp']['some_option'] = 'default_value'
250
251
class MyApp(App):
252
class Meta:
253
label = 'myapp'
254
config_defaults = CONFIG
255
config_files = ['/etc/myapp.conf', '~/.myapp.conf']
256
257
with MyApp() as app:
258
app.setup()
259
print(f"Debug mode: {app.config.get('myapp', 'debug')}")
260
print(f"Option value: {app.config.get('myapp', 'some_option')}")
261
app.run()
262
```
263
264
### Testing Application
265
266
```python
267
from cement import TestApp
268
269
def test_myapp():
270
with TestApp() as app:
271
app.setup()
272
# Test application functionality
273
assert app.config.get('myapp', 'debug') == True
274
app.run()
275
```
276
277
### Application with Extensions
278
279
```python
280
from cement import App
281
282
class MyApp(App):
283
class Meta:
284
label = 'myapp'
285
extensions = ['colorlog', 'jinja2', 'yaml']
286
config_handler = 'yaml'
287
template_handler = 'jinja2'
288
log_handler = 'colorlog'
289
290
with MyApp() as app:
291
app.setup()
292
app.log.info('Application started with extensions')
293
app.run()
294
```
295
296
### Context Manager Usage
297
298
The recommended pattern is to use applications as context managers to ensure proper setup and cleanup:
299
300
```python
301
from cement import App
302
303
# Recommended approach - automatic setup/cleanup
304
with MyApp() as app:
305
app.run()
306
307
# Manual approach - requires explicit calls
308
app = MyApp()
309
try:
310
app.setup()
311
app.run()
312
finally:
313
app.close()
314
```