0
# Input/Output System
1
2
The I/O system provides comprehensive input and output management for CLI applications. It handles input from various sources (command line arguments, strings, user interaction), manages output to different destinations (stdout, stderr, files, memory buffers), and supports verbosity levels and formatting.
3
4
## Capabilities
5
6
### IO Coordination Class
7
8
The main IO class coordinates input, output, and error output streams with verbosity control.
9
10
```python { .api }
11
class IO:
12
def __init__(self, input: Input, output: Output, error_output: Output) -> None:
13
"""
14
Create an IO coordinator.
15
16
Args:
17
input (Input): Input stream for reading user input
18
output (Output): Primary output stream
19
error_output (Output): Error output stream
20
"""
21
22
def read(self, length: int, default: str = "") -> str:
23
"""
24
Read input from the input stream.
25
26
Args:
27
length (int): Maximum length to read
28
default (str): Default value if no input
29
30
Returns:
31
str: Input text
32
"""
33
34
def write(self, messages: str | Iterable[str], new_line: bool = False) -> None:
35
"""
36
Write messages to output.
37
38
Args:
39
messages (str | Iterable[str]): Messages to write
40
new_line (bool): Whether to add newline after each message
41
"""
42
43
def write_line(self, messages: str | Iterable[str]) -> None:
44
"""
45
Write messages to output with newlines.
46
47
Args:
48
messages (str | Iterable[str]): Messages to write
49
"""
50
51
def write_error(self, messages: str | Iterable[str], new_line: bool = False) -> None:
52
"""
53
Write messages to error output.
54
55
Args:
56
messages (str | Iterable[str]): Error messages to write
57
new_line (bool): Whether to add newline
58
"""
59
60
def write_error_line(self, messages: str | Iterable[str]) -> None:
61
"""
62
Write messages to error output with newlines.
63
64
Args:
65
messages (str | Iterable[str]): Error messages to write
66
"""
67
68
def is_interactive(self) -> bool:
69
"""
70
Check if input is interactive (TTY).
71
72
Returns:
73
bool: True if interactive
74
"""
75
76
def is_decorated(self) -> bool:
77
"""
78
Check if output supports decoration (colors/formatting).
79
80
Returns:
81
bool: True if decorated output is supported
82
"""
83
84
def set_verbosity(self, verbosity: Verbosity) -> None:
85
"""
86
Set the verbosity level.
87
88
Args:
89
verbosity (Verbosity): Verbosity level to set
90
"""
91
92
@property
93
def verbosity(self) -> Verbosity:
94
"""Get the current verbosity level."""
95
96
@property
97
def input(self) -> Input:
98
"""Get the input stream."""
99
100
@property
101
def output(self) -> Output:
102
"""Get the output stream."""
103
104
@property
105
def error_output(self) -> Output:
106
"""Get the error output stream."""
107
```
108
109
### Specialized IO Classes
110
111
Alternative IO implementations for different use cases.
112
113
```python { .api }
114
class BufferedIO(IO):
115
"""IO implementation that buffers output in memory for testing."""
116
117
def fetch_output(self) -> str:
118
"""
119
Fetch the buffered output content.
120
121
Returns:
122
str: All output written since last fetch
123
"""
124
125
def fetch_error(self) -> str:
126
"""
127
Fetch the buffered error output content.
128
129
Returns:
130
str: All error output written since last fetch
131
"""
132
133
class NullIO(IO):
134
"""IO implementation that discards all output."""
135
pass
136
```
137
138
## Input System
139
140
### Input Base Class
141
142
Abstract base class for all input sources.
143
144
```python { .api }
145
class Input:
146
def __init__(self, definition: Definition | None = None) -> None: ...
147
148
def bind(self, definition: Definition) -> None:
149
"""Bind input to a command definition."""
150
151
def validate(self) -> None:
152
"""Validate input against bound definition."""
153
154
def get_arguments(self) -> dict[str, Any]:
155
"""Get all arguments as dictionary."""
156
157
def get_argument(self, name: str) -> Any:
158
"""Get argument value by name."""
159
160
def set_argument(self, name: str, value: Any) -> None:
161
"""Set argument value."""
162
163
def has_argument(self, name: str) -> bool:
164
"""Check if argument exists."""
165
166
def get_options(self) -> dict[str, Any]:
167
"""Get all options as dictionary."""
168
169
def get_option(self, name: str) -> Any:
170
"""Get option value by name."""
171
172
def set_option(self, name: str, value: Any) -> None:
173
"""Set option value."""
174
175
def has_option(self, name: str) -> bool:
176
"""Check if option exists."""
177
178
def is_interactive(self) -> bool:
179
"""Check if input is interactive."""
180
181
@property
182
def definition(self) -> Definition:
183
"""Get the input definition."""
184
```
185
186
### Input Implementations
187
188
Concrete input classes for different input sources.
189
190
```python { .api }
191
class ArgvInput(Input):
192
"""Input from command line arguments (sys.argv)."""
193
194
def __init__(self, argv: list[str] | None = None, definition: Definition | None = None) -> None:
195
"""
196
Create input from command line arguments.
197
198
Args:
199
argv (list[str] | None): Argument list, defaults to sys.argv
200
definition (Definition | None): Input definition
201
"""
202
203
class StringInput(Input):
204
"""Input from a string for testing."""
205
206
def __init__(self, input_str: str, definition: Definition | None = None) -> None:
207
"""
208
Create input from a string.
209
210
Args:
211
input_str (str): Input string to parse
212
definition (Definition | None): Input definition
213
"""
214
```
215
216
## Output System
217
218
### Output Base Class
219
220
Abstract base class for all output destinations.
221
222
```python { .api }
223
class Output:
224
def __init__(self, verbosity: Verbosity = Verbosity.NORMAL, decorated: bool | None = None,
225
formatter: Formatter | None = None) -> None: ...
226
227
def write(self, messages: str | Iterable[str], new_line: bool = False,
228
type: Type = Type.NORMAL) -> None:
229
"""
230
Write messages to output.
231
232
Args:
233
messages (str | Iterable[str]): Messages to write
234
new_line (bool): Whether to add newlines
235
type (Type): Output type (NORMAL, RAW, PLAIN)
236
"""
237
238
def write_line(self, messages: str | Iterable[str], type: Type = Type.NORMAL) -> None:
239
"""Write messages with newlines."""
240
241
def set_verbosity(self, level: Verbosity) -> None:
242
"""Set verbosity level."""
243
244
def get_verbosity(self) -> Verbosity:
245
"""Get current verbosity level."""
246
247
def is_quiet(self) -> bool:
248
"""Check if output is in quiet mode."""
249
250
def is_verbose(self) -> bool:
251
"""Check if output is in verbose mode."""
252
253
def is_very_verbose(self) -> bool:
254
"""Check if output is in very verbose mode."""
255
256
def is_debug(self) -> bool:
257
"""Check if output is in debug mode."""
258
259
def set_decorated(self, decorated: bool) -> None:
260
"""Enable/disable output decoration."""
261
262
def is_decorated(self) -> bool:
263
"""Check if output is decorated."""
264
265
def set_formatter(self, formatter: Formatter) -> None:
266
"""Set the output formatter."""
267
268
def get_formatter(self) -> Formatter:
269
"""Get the output formatter."""
270
```
271
272
### Output Implementations
273
274
Concrete output classes for different output destinations.
275
276
```python { .api }
277
class StreamOutput(Output):
278
"""Output to a stream (stdout, stderr, file)."""
279
280
def __init__(self, stream: TextIO, verbosity: Verbosity = Verbosity.NORMAL,
281
decorated: bool | None = None, formatter: Formatter | None = None) -> None:
282
"""
283
Create output to a stream.
284
285
Args:
286
stream (TextIO): Output stream
287
verbosity (Verbosity): Verbosity level
288
decorated (bool | None): Whether to use decoration
289
formatter (Formatter | None): Output formatter
290
"""
291
292
class BufferedOutput(Output):
293
"""Output buffered in memory."""
294
295
def fetch(self) -> str:
296
"""
297
Fetch and clear the buffer content.
298
299
Returns:
300
str: Buffered output content
301
"""
302
303
def get_content(self) -> str:
304
"""
305
Get buffer content without clearing.
306
307
Returns:
308
str: Current buffer content
309
"""
310
311
def clear(self) -> None:
312
"""Clear the buffer."""
313
314
class NullOutput(Output):
315
"""Output that discards all content."""
316
pass
317
318
class SectionOutput(Output):
319
"""Output that can be updated in sections."""
320
321
def clear(self, lines: int | None = None) -> None:
322
"""
323
Clear lines from output.
324
325
Args:
326
lines (int | None): Number of lines to clear
327
"""
328
329
def overwrite(self, messages: str | Iterable[str]) -> None:
330
"""
331
Overwrite the current section content.
332
333
Args:
334
messages (str | Iterable[str]): New content
335
"""
336
```
337
338
## Verbosity and Output Types
339
340
### Verbosity Levels
341
342
Enumeration of verbosity levels for controlling output detail.
343
344
```python { .api }
345
class Verbosity(Enum):
346
QUIET = 16 # Suppress all output except errors
347
NORMAL = 32 # Normal output level
348
VERBOSE = 64 # Increased verbosity (-v)
349
VERY_VERBOSE = 128 # High verbosity (-vv)
350
DEBUG = 256 # Debug information (-vvv)
351
```
352
353
### Output Types
354
355
Enumeration of output formatting types.
356
357
```python { .api }
358
class Type(Enum):
359
NORMAL = 1 # Normal formatted output
360
RAW = 2 # Raw output without formatting
361
PLAIN = 4 # Plain output without colors
362
```
363
364
## Usage Examples
365
366
### Basic IO Setup
367
368
```python
369
from cleo.io.io import IO
370
from cleo.io.inputs.argv_input import ArgvInput
371
from cleo.io.outputs.stream_output import StreamOutput
372
import sys
373
374
# Create IO with standard streams
375
input = ArgvInput()
376
output = StreamOutput(sys.stdout)
377
error_output = StreamOutput(sys.stderr)
378
io = IO(input, output, error_output)
379
380
# Write output
381
io.write_line("Processing data...")
382
io.write_error_line("Warning: deprecated option used")
383
```
384
385
### Testing with Buffered IO
386
387
```python
388
from cleo.io.buffered_io import BufferedIO
389
from cleo.io.inputs.string_input import StringInput
390
391
# Create buffered IO for testing
392
input = StringInput("test-file --verbose")
393
io = BufferedIO(input)
394
395
# Run command with buffered IO
396
command.run(io)
397
398
# Check output
399
output = io.fetch_output()
400
errors = io.fetch_error()
401
assert "Success" in output
402
```
403
404
### Verbosity Control
405
406
```python
407
from cleo.io.outputs.output import Verbosity
408
409
# Set verbosity level
410
io.set_verbosity(Verbosity.VERBOSE)
411
412
# Check verbosity in commands
413
if io.output.is_verbose():
414
io.write_line("Detailed processing information...")
415
416
if io.output.is_debug():
417
io.write_line(f"Debug: processing {len(items)} items")
418
419
# Write with specific verbosity requirements
420
io.write_line("Always shown", verbosity=Verbosity.NORMAL)
421
io.write_line("Only in verbose mode", verbosity=Verbosity.VERBOSE)
422
```
423
424
### Section Output for Live Updates
425
426
```python
427
from cleo.io.outputs.section_output import SectionOutput
428
429
# Create section output for live updates
430
section = output.section()
431
432
# Update progress
433
for i in range(100):
434
section.overwrite(f"Progress: {i}%")
435
time.sleep(0.1)
436
437
section.overwrite("Complete!")
438
```