clicycle 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clicycle-0.1.0/.gitignore +54 -0
- clicycle-0.1.0/LICENSE +21 -0
- clicycle-0.1.0/PKG-INFO +631 -0
- clicycle-0.1.0/README.md +595 -0
- clicycle-0.1.0/examples/README.md +75 -0
- clicycle-0.1.0/examples/basic_usage.py +120 -0
- clicycle-0.1.0/examples/click_integration.py +244 -0
- clicycle-0.1.0/examples/theming_example.py +193 -0
- clicycle-0.1.0/pyproject.toml +124 -0
- clicycle-0.1.0/src/clicycle/__init__.py +41 -0
- clicycle-0.1.0/src/clicycle/core.py +331 -0
- clicycle-0.1.0/src/clicycle/prompts.py +40 -0
- clicycle-0.1.0/src/clicycle/render.py +429 -0
- clicycle-0.1.0/src/clicycle/theme.py +151 -0
- clicycle-0.1.0/tests/__init__.py +1 -0
- clicycle-0.1.0/tests/optimized_performance_test.py +199 -0
- clicycle-0.1.0/tests/performance_test.py +233 -0
- clicycle-0.1.0/tests/test_clicycle.py +163 -0
- clicycle-0.1.0/tests/test_prompts.py +97 -0
- clicycle-0.1.0/tests/test_theme.py +163 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
|
|
10
|
+
# Build artifacts
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
*.egg-info/
|
|
14
|
+
|
|
15
|
+
# Testing
|
|
16
|
+
htmlcov/
|
|
17
|
+
.coverage
|
|
18
|
+
.coverage.*
|
|
19
|
+
coverage.xml
|
|
20
|
+
coverage.json
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.tox/
|
|
23
|
+
.nox/
|
|
24
|
+
|
|
25
|
+
# Tools
|
|
26
|
+
.ruff_cache/
|
|
27
|
+
.mypy_cache/
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Project specific
|
|
38
|
+
uv.lock
|
|
39
|
+
.pdm-python
|
|
40
|
+
.python-version
|
|
41
|
+
|
|
42
|
+
# Logs
|
|
43
|
+
*.log
|
|
44
|
+
|
|
45
|
+
# Documentation
|
|
46
|
+
docs/_build/
|
|
47
|
+
site/
|
|
48
|
+
|
|
49
|
+
# Temporary files
|
|
50
|
+
*.tmp
|
|
51
|
+
*.bak
|
|
52
|
+
*~
|
|
53
|
+
.*.swp
|
|
54
|
+
.*.swo
|
clicycle-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Living Content
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
clicycle-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clicycle
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: HTML-like CLI framework with self-spacing components and Rich theming
|
|
5
|
+
Project-URL: Homepage, https://github.com/Living-Content/clicycle
|
|
6
|
+
Project-URL: Repository, https://github.com/Living-Content/clicycle.git
|
|
7
|
+
Project-URL: Issues, https://github.com/Living-Content/clicycle/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/Living-Content/clicycle#readme
|
|
9
|
+
Author-email: Living Content <hello@livingcontent.co>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,components,rich,terminal,ui
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: System :: Shells
|
|
25
|
+
Classifier: Topic :: Terminals
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Requires-Dist: click>=8.2.1
|
|
28
|
+
Requires-Dist: rich>=13.9.4
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: mypy>=1.17.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.4.1; extra == 'dev'
|
|
33
|
+
Requires-Dist: ruff>=0.12.4; extra == 'dev'
|
|
34
|
+
Requires-Dist: types-click>=7.1.8; extra == 'dev'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# Clicycle
|
|
38
|
+
|
|
39
|
+
> HTML-like CLI framework with self-spacing components and Rich theming
|
|
40
|
+
|
|
41
|
+
**Clicycle** is a modern Python CLI framework that provides React/HTML-like components for building beautiful command-line interfaces with automatic spacing and Rich theming.
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Rich theming** - Comprehensive styling with icons, typography, and layout controls
|
|
46
|
+
- **Automatic spacing** - Components manage their own spacing like HTML elements
|
|
47
|
+
- **Component-based** - Familiar React/HTML-like API with composable components
|
|
48
|
+
- **Type-safe** - Full type hints and IDE support
|
|
49
|
+
- **Smart tables** - Automatically sized columns with intelligent formatting
|
|
50
|
+
- **Code highlighting** - Syntax-highlighted code blocks with line numbers
|
|
51
|
+
- **Progress tracking** - Built-in progress bars and spinners
|
|
52
|
+
- **Interactive prompts** - Properly spaced input prompts and confirmations
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
### Using uv (Recommended)
|
|
57
|
+
|
|
58
|
+
[uv](https://github.com/astral-sh/uv) is a fast Python package installer and virtual environment manager.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Install clicycle
|
|
62
|
+
uv add clicycle
|
|
63
|
+
|
|
64
|
+
# Or install globally
|
|
65
|
+
uv tool install clicycle
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Using pip (not recommended)
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install clicycle
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Development Installation
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
git clone https://github.com/yourusername/clicycle.git
|
|
78
|
+
cd clicycle
|
|
79
|
+
|
|
80
|
+
# Using uv (recommended)
|
|
81
|
+
uv venv
|
|
82
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
83
|
+
uv pip install -e ".[dev]"
|
|
84
|
+
|
|
85
|
+
# Using pip
|
|
86
|
+
pip install -e ".[dev]"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Quick Start
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from clicycle import Clicycle
|
|
93
|
+
|
|
94
|
+
# Create a CLI instance
|
|
95
|
+
cli = Clicycle(app_name="MyApp")
|
|
96
|
+
|
|
97
|
+
# Display a header
|
|
98
|
+
cli.header("Welcome", "Getting started with Clicycle")
|
|
99
|
+
|
|
100
|
+
# Show different message types
|
|
101
|
+
cli.info("This is an info message")
|
|
102
|
+
cli.success("Operation completed successfully!")
|
|
103
|
+
cli.warning("This is a warning")
|
|
104
|
+
cli.error("Something went wrong")
|
|
105
|
+
|
|
106
|
+
# Display a table
|
|
107
|
+
data = [
|
|
108
|
+
{"Name": "Alice", "Age": 30, "City": "New York"},
|
|
109
|
+
{"Name": "Bob", "Age": 25, "City": "San Francisco"},
|
|
110
|
+
{"Name": "Charlie", "Age": 35, "City": "Chicago"},
|
|
111
|
+
]
|
|
112
|
+
cli.table(data, title="User Information")
|
|
113
|
+
|
|
114
|
+
# Show code with syntax highlighting
|
|
115
|
+
code = '''
|
|
116
|
+
def hello_world():
|
|
117
|
+
print("Hello, Clicycle!")
|
|
118
|
+
'''
|
|
119
|
+
cli.code(code, language="python", title="Example Code")
|
|
120
|
+
|
|
121
|
+
# Interactive prompts
|
|
122
|
+
name = cli.prompt("What's your name?")
|
|
123
|
+
confirmed = cli.confirm("Do you want to continue?")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Components
|
|
127
|
+
|
|
128
|
+
### Headers and Sections
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from clicycle import Clicycle
|
|
132
|
+
|
|
133
|
+
cli = Clicycle()
|
|
134
|
+
|
|
135
|
+
# Main header with optional app branding
|
|
136
|
+
cli.header("Main Title", "Optional subtitle", app_name="MyApp")
|
|
137
|
+
|
|
138
|
+
# Section dividers
|
|
139
|
+
cli.section("Configuration")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Text Messages
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# Different message types with automatic icons
|
|
146
|
+
cli.info("Information message")
|
|
147
|
+
cli.success("Success message")
|
|
148
|
+
cli.warning("Warning message")
|
|
149
|
+
cli.error("Error message")
|
|
150
|
+
cli.debug("Debug message") # Only shown in verbose mode
|
|
151
|
+
|
|
152
|
+
# List items
|
|
153
|
+
cli.list("First item")
|
|
154
|
+
cli.list("Second item")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Tables
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
# Simple table
|
|
161
|
+
data = [
|
|
162
|
+
{"Name": "Alice", "Score": 95},
|
|
163
|
+
{"Name": "Bob", "Score": 87},
|
|
164
|
+
]
|
|
165
|
+
cli.table(data)
|
|
166
|
+
|
|
167
|
+
# Table with title
|
|
168
|
+
cli.table(data, title="Test Results")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Code Display
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# Python code with line numbers
|
|
175
|
+
cli.code('''
|
|
176
|
+
def fibonacci(n):
|
|
177
|
+
if n <= 1:
|
|
178
|
+
return n
|
|
179
|
+
return fibonacci(n-1) + fibonacci(n-2)
|
|
180
|
+
''', language="python", title="Fibonacci Function")
|
|
181
|
+
|
|
182
|
+
# JSON data
|
|
183
|
+
cli.json({"name": "Alice", "age": 30}, title="User Data")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Progress and Spinners
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# Simple spinner
|
|
190
|
+
with cli.spinner("Loading data..."):
|
|
191
|
+
time.sleep(2)
|
|
192
|
+
|
|
193
|
+
# Progress bar
|
|
194
|
+
with cli.progress("Processing files") as progress_cli:
|
|
195
|
+
for i in range(100):
|
|
196
|
+
progress_cli.update_progress(i, f"Processing file {i}")
|
|
197
|
+
time.sleep(0.1)
|
|
198
|
+
|
|
199
|
+
# Multi-task progress
|
|
200
|
+
with cli.multi_progress("Multiple tasks") as progress:
|
|
201
|
+
task1 = progress.add_task("Task 1", total=100, short_id="T1")
|
|
202
|
+
task2 = progress.add_task("Task 2", total=50, short_id="T2")
|
|
203
|
+
|
|
204
|
+
for i in range(100):
|
|
205
|
+
progress.update(task1, advance=1)
|
|
206
|
+
if i % 2 == 0:
|
|
207
|
+
progress.update(task2, advance=1)
|
|
208
|
+
time.sleep(0.1)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Interactive Prompts
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
# Basic prompts
|
|
215
|
+
name = cli.prompt("Enter your name")
|
|
216
|
+
age = cli.prompt("Enter your age", type=int)
|
|
217
|
+
confirmed = cli.confirm("Are you sure?")
|
|
218
|
+
|
|
219
|
+
# Selection from list
|
|
220
|
+
from clicycle import select_from_list
|
|
221
|
+
|
|
222
|
+
option = select_from_list(
|
|
223
|
+
"environment",
|
|
224
|
+
["development", "staging", "production"],
|
|
225
|
+
default="development",
|
|
226
|
+
cli=cli
|
|
227
|
+
)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Grouping with Blocks
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# Group related content
|
|
234
|
+
cli.section("User Information")
|
|
235
|
+
with cli.block():
|
|
236
|
+
cli.info("Processing user data...")
|
|
237
|
+
cli.success("User validated")
|
|
238
|
+
cli.info("Creating profile...")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Summary Data
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
# Key-value summaries
|
|
245
|
+
summary_data = [
|
|
246
|
+
{"label": "Total Files", "value": 1250},
|
|
247
|
+
{"label": "Processed", "value": 1200},
|
|
248
|
+
{"label": "Errors", "value": 50},
|
|
249
|
+
{"label": "Success Rate", "value": "96%"},
|
|
250
|
+
]
|
|
251
|
+
cli.summary(summary_data)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Theming
|
|
255
|
+
|
|
256
|
+
Clicycle provides comprehensive theming capabilities to match your application's branding and style preferences.
|
|
257
|
+
|
|
258
|
+
### Basic Theming
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from clicycle import Clicycle, Theme, Icons, Typography
|
|
262
|
+
|
|
263
|
+
# Create custom theme
|
|
264
|
+
custom_theme = Theme(
|
|
265
|
+
icons=Icons(
|
|
266
|
+
success="✅",
|
|
267
|
+
error="❌",
|
|
268
|
+
info="💡",
|
|
269
|
+
warning="⚠️",
|
|
270
|
+
debug="🔍",
|
|
271
|
+
bullet="▶"
|
|
272
|
+
),
|
|
273
|
+
typography=Typography(
|
|
274
|
+
header_style="bold magenta",
|
|
275
|
+
success_style="bold green",
|
|
276
|
+
error_style="bold red on white",
|
|
277
|
+
info_style="bold blue",
|
|
278
|
+
warning_style="bold yellow"
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
cli = Clicycle(theme=custom_theme)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Complete Theme Customization
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
from clicycle import Clicycle, Theme, Icons, Typography, Layout, ComponentSpacing
|
|
289
|
+
|
|
290
|
+
# Create a comprehensive custom theme
|
|
291
|
+
professional_theme = Theme(
|
|
292
|
+
icons=Icons(
|
|
293
|
+
success="✓",
|
|
294
|
+
error="✗",
|
|
295
|
+
info="ℹ",
|
|
296
|
+
warning="⚠",
|
|
297
|
+
debug="→",
|
|
298
|
+
bullet="•"
|
|
299
|
+
),
|
|
300
|
+
typography=Typography(
|
|
301
|
+
# Headers and sections
|
|
302
|
+
header_style="bold white on blue",
|
|
303
|
+
section_style="bold cyan underline",
|
|
304
|
+
|
|
305
|
+
# Message styles
|
|
306
|
+
success_style="bold green",
|
|
307
|
+
error_style="bold red",
|
|
308
|
+
info_style="cyan",
|
|
309
|
+
warning_style="bold yellow",
|
|
310
|
+
debug_style="dim white",
|
|
311
|
+
|
|
312
|
+
# Table and code styles
|
|
313
|
+
table_header_style="bold white on black",
|
|
314
|
+
code_style="bright_black on white"
|
|
315
|
+
),
|
|
316
|
+
layout=Layout(
|
|
317
|
+
table_style="rounded",
|
|
318
|
+
table_header_style="bold magenta",
|
|
319
|
+
table_row_styles=["none", "dim"],
|
|
320
|
+
code_theme="github-dark"
|
|
321
|
+
),
|
|
322
|
+
spacing=ComponentSpacing(
|
|
323
|
+
after_header=2,
|
|
324
|
+
after_section=1,
|
|
325
|
+
between_components=1,
|
|
326
|
+
before_table=1,
|
|
327
|
+
after_table=1,
|
|
328
|
+
before_code=1,
|
|
329
|
+
after_code=1
|
|
330
|
+
)
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Use the professional theme
|
|
334
|
+
cli = Clicycle(theme=professional_theme)
|
|
335
|
+
|
|
336
|
+
# Demonstrate the themed output
|
|
337
|
+
cli.header("Professional Application", "With custom styling")
|
|
338
|
+
cli.section("System Status")
|
|
339
|
+
cli.success("All systems operational")
|
|
340
|
+
cli.info("Current version: 2.1.0")
|
|
341
|
+
cli.warning("Maintenance scheduled for tonight")
|
|
342
|
+
|
|
343
|
+
# Table with professional styling
|
|
344
|
+
data = [
|
|
345
|
+
{"Service": "API", "Status": "✓ Running", "Uptime": "99.9%"},
|
|
346
|
+
{"Service": "Database", "Status": "✓ Running", "Uptime": "99.8%"},
|
|
347
|
+
{"Service": "Cache", "Status": "⚠ Warning", "Uptime": "98.5%"}
|
|
348
|
+
]
|
|
349
|
+
cli.table(data, title="Service Health")
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Theme Components
|
|
353
|
+
|
|
354
|
+
- **Icons** - All symbols and indicators (success, error, info, warning, debug, bullet)
|
|
355
|
+
- **Typography** - Text styles for every component type
|
|
356
|
+
- **Layout** - Table styling, code themes, and visual presentation
|
|
357
|
+
- **ComponentSpacing** - Precise control over spacing between all component types
|
|
358
|
+
|
|
359
|
+
### Predefined Themes
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
# Minimal theme for clean output
|
|
363
|
+
minimal_theme = Theme(
|
|
364
|
+
icons=Icons(success="", error="", info="", warning="", debug="", bullet="·"),
|
|
365
|
+
typography=Typography(
|
|
366
|
+
header_style="bold",
|
|
367
|
+
success_style="green",
|
|
368
|
+
error_style="red",
|
|
369
|
+
info_style="blue",
|
|
370
|
+
warning_style="yellow"
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# Colorful theme for engaging interfaces
|
|
375
|
+
colorful_theme = Theme(
|
|
376
|
+
icons=Icons(
|
|
377
|
+
success="🎉",
|
|
378
|
+
error="💥",
|
|
379
|
+
info="💬",
|
|
380
|
+
warning="🚨",
|
|
381
|
+
debug="🔧",
|
|
382
|
+
bullet="🔸"
|
|
383
|
+
),
|
|
384
|
+
typography=Typography(
|
|
385
|
+
header_style="bold magenta on black",
|
|
386
|
+
success_style="bold green on black",
|
|
387
|
+
error_style="bold red on yellow",
|
|
388
|
+
info_style="bold blue on white",
|
|
389
|
+
warning_style="bold black on yellow"
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
cli = Clicycle(theme=minimal_theme) # or colorful_theme
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Advanced Usage
|
|
397
|
+
|
|
398
|
+
### Custom CLI Instance
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
from clicycle import Clicycle, Theme
|
|
402
|
+
|
|
403
|
+
# Create CLI with custom settings
|
|
404
|
+
cli = Clicycle(
|
|
405
|
+
width=120, # Terminal width
|
|
406
|
+
app_name="MyApp", # App branding in headers
|
|
407
|
+
theme=custom_theme # Custom theme
|
|
408
|
+
)
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Integration with Click
|
|
412
|
+
|
|
413
|
+
Clicycle works seamlessly with Click for command-line applications:
|
|
414
|
+
|
|
415
|
+
```python
|
|
416
|
+
import click
|
|
417
|
+
from clicycle import Clicycle
|
|
418
|
+
|
|
419
|
+
@click.command()
|
|
420
|
+
@click.option('--verbose', '-v', is_flag=True)
|
|
421
|
+
def main(verbose):
|
|
422
|
+
cli = Clicycle()
|
|
423
|
+
|
|
424
|
+
if verbose:
|
|
425
|
+
cli.debug("Verbose mode enabled")
|
|
426
|
+
|
|
427
|
+
cli.header("My Application", "Version 1.0")
|
|
428
|
+
cli.info("Application started")
|
|
429
|
+
|
|
430
|
+
if __name__ == '__main__':
|
|
431
|
+
main()
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Error Handling
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
try:
|
|
438
|
+
# Some operation
|
|
439
|
+
result = risky_operation()
|
|
440
|
+
cli.success(f"Operation completed: {result}")
|
|
441
|
+
except Exception as e:
|
|
442
|
+
cli.error(f"Operation failed: {e}")
|
|
443
|
+
cli.suggestions([
|
|
444
|
+
"Check your input parameters",
|
|
445
|
+
"Verify network connectivity",
|
|
446
|
+
"Try again with --verbose flag"
|
|
447
|
+
])
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Performance
|
|
451
|
+
|
|
452
|
+
Clicycle is optimized for CLI applications with minimal overhead while providing rich functionality. Here's how to benchmark performance in your applications:
|
|
453
|
+
|
|
454
|
+
### Performance Testing
|
|
455
|
+
|
|
456
|
+
```python
|
|
457
|
+
#!/usr/bin/env python3
|
|
458
|
+
"""Simple performance benchmark for clicycle."""
|
|
459
|
+
|
|
460
|
+
import io
|
|
461
|
+
import time
|
|
462
|
+
from rich.console import Console
|
|
463
|
+
from clicycle import Clicycle
|
|
464
|
+
|
|
465
|
+
def benchmark_clicycle():
|
|
466
|
+
"""Benchmark clicycle performance against alternatives."""
|
|
467
|
+
|
|
468
|
+
def measure_time(func):
|
|
469
|
+
"""Simple timing decorator."""
|
|
470
|
+
start_time = time.perf_counter()
|
|
471
|
+
func()
|
|
472
|
+
end_time = time.perf_counter()
|
|
473
|
+
return (end_time - start_time) * 1000 # Convert to milliseconds
|
|
474
|
+
|
|
475
|
+
# Test clicycle basic output
|
|
476
|
+
def test_clicycle():
|
|
477
|
+
cli = Clicycle()
|
|
478
|
+
# Capture output to avoid terminal spam during benchmarking
|
|
479
|
+
cli.stream.console = Console(file=io.StringIO())
|
|
480
|
+
|
|
481
|
+
cli.header("Performance Test", "Basic Output")
|
|
482
|
+
cli.info("This is an info message")
|
|
483
|
+
cli.success("This is a success message")
|
|
484
|
+
cli.warning("This is a warning message")
|
|
485
|
+
cli.error("This is an error message")
|
|
486
|
+
|
|
487
|
+
# Test table rendering
|
|
488
|
+
data = [
|
|
489
|
+
{"Name": f"User_{i}", "Score": i * 10, "Status": "Active"}
|
|
490
|
+
for i in range(100)
|
|
491
|
+
]
|
|
492
|
+
cli.table(data, title="Performance Test Data")
|
|
493
|
+
|
|
494
|
+
# Test raw Rich for comparison
|
|
495
|
+
def test_raw_rich():
|
|
496
|
+
console = Console(file=io.StringIO())
|
|
497
|
+
console.print("[bold blue]Performance Test[/bold blue]")
|
|
498
|
+
console.print("ℹ This is an info message")
|
|
499
|
+
console.print("✓ This is a success message")
|
|
500
|
+
console.print("⚠ This is a warning message")
|
|
501
|
+
console.print("✗ This is an error message")
|
|
502
|
+
|
|
503
|
+
# Run benchmarks
|
|
504
|
+
clicycle_time = measure_time(test_clicycle)
|
|
505
|
+
rich_time = measure_time(test_raw_rich)
|
|
506
|
+
|
|
507
|
+
# Results
|
|
508
|
+
cli = Clicycle()
|
|
509
|
+
cli.header("Performance Results")
|
|
510
|
+
|
|
511
|
+
results = [
|
|
512
|
+
{"Test": "Clicycle (full features)", "Time (ms)": f"{clicycle_time:.2f}"},
|
|
513
|
+
{"Test": "Raw Rich (basic)", "Time (ms)": f"{rich_time:.2f}"},
|
|
514
|
+
{"Test": "Overhead", "Time (ms)": f"{clicycle_time - rich_time:.2f}"}
|
|
515
|
+
]
|
|
516
|
+
cli.table(results, title="Benchmark Comparison")
|
|
517
|
+
|
|
518
|
+
overhead_percent = ((clicycle_time / rich_time) - 1) * 100
|
|
519
|
+
cli.info(f"Clicycle overhead: {overhead_percent:.1f}% vs raw Rich")
|
|
520
|
+
|
|
521
|
+
if clicycle_time < 50: # Less than 50ms is excellent for CLI
|
|
522
|
+
cli.success("Performance is excellent for CLI applications")
|
|
523
|
+
elif clicycle_time < 100:
|
|
524
|
+
cli.info("Performance is good for most CLI use cases")
|
|
525
|
+
else:
|
|
526
|
+
cli.warning("Consider optimizing for high-frequency operations")
|
|
527
|
+
|
|
528
|
+
if __name__ == "__main__":
|
|
529
|
+
benchmark_clicycle()
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Performance Characteristics
|
|
533
|
+
|
|
534
|
+
Based on our benchmarks, Clicycle delivers:
|
|
535
|
+
|
|
536
|
+
- **Startup time**: ~0.07ms (virtually instant)
|
|
537
|
+
- **Basic output**: ~1-2ms for typical message combinations
|
|
538
|
+
- **Large tables**: ~100ms for 1000 rows (same as raw Rich)
|
|
539
|
+
- **Memory usage**: Minimal overhead (~0.1MB for typical usage)
|
|
540
|
+
|
|
541
|
+
### Performance Tips
|
|
542
|
+
|
|
543
|
+
- **Reuse CLI instances** - Create once, use many times
|
|
544
|
+
- **Batch operations** - Use `with cli.block():` to group related output
|
|
545
|
+
- **Table pagination** - For large datasets, consider pagination or streaming
|
|
546
|
+
- **Caching themes** - Custom themes are automatically cached for performance
|
|
547
|
+
|
|
548
|
+
### When to Optimize
|
|
549
|
+
|
|
550
|
+
Clicycle's performance is designed for human-readable CLI output where microsecond differences are imperceptible. Consider optimization only for:
|
|
551
|
+
|
|
552
|
+
- High-frequency logging (>1000 operations/second)
|
|
553
|
+
- Real-time data streaming interfaces
|
|
554
|
+
- Resource-constrained environments
|
|
555
|
+
- Batch processing of large datasets
|
|
556
|
+
|
|
557
|
+
For most CLI applications, Clicycle's rich features and automatic spacing provide excellent value with negligible performance impact.
|
|
558
|
+
|
|
559
|
+
## API Reference
|
|
560
|
+
|
|
561
|
+
### Clicycle Class
|
|
562
|
+
|
|
563
|
+
The main class for creating CLI interfaces.
|
|
564
|
+
|
|
565
|
+
#### Constructor
|
|
566
|
+
|
|
567
|
+
```python
|
|
568
|
+
Clicycle(width: int = 100, theme: Theme | None = None, app_name: str | None = None)
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
#### Methods
|
|
572
|
+
|
|
573
|
+
- `header(title: str, subtitle: str = None, app_name: str = None)` - Display header
|
|
574
|
+
- `section(title: str)` - Display section divider
|
|
575
|
+
- `info/success/warning/error/debug(message: str)` - Display styled messages
|
|
576
|
+
- `table(data: list[dict], title: str = None)` - Display data table
|
|
577
|
+
- `code(code: str, language: str = "python", title: str = None, line_numbers: bool = True)` - Display code
|
|
578
|
+
- `json(data: dict, title: str = None)` - Display JSON data
|
|
579
|
+
- `summary(data: list[dict])` - Display key-value summary
|
|
580
|
+
- `list(item: str)` - Display list item
|
|
581
|
+
- `prompt(text: str, **kwargs)` - Interactive prompt
|
|
582
|
+
- `confirm(text: str, **kwargs)` - Interactive confirmation
|
|
583
|
+
- `suggestions(suggestions: list[str])` - Display suggestion list
|
|
584
|
+
- `spinner(message: str)` - Context manager for spinner
|
|
585
|
+
- `progress(description: str)` - Context manager for progress bar
|
|
586
|
+
- `multi_progress(description: str)` - Context manager for multi-task progress
|
|
587
|
+
- `block()` - Context manager for grouping components
|
|
588
|
+
- `clear()` - Clear terminal and reset
|
|
589
|
+
|
|
590
|
+
## Contributing
|
|
591
|
+
|
|
592
|
+
1. Fork the repository
|
|
593
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
594
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
595
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
596
|
+
5. Open a Pull Request
|
|
597
|
+
|
|
598
|
+
## Development
|
|
599
|
+
|
|
600
|
+
```bash
|
|
601
|
+
# Install development dependencies using uv (recommended)
|
|
602
|
+
uv pip install -e ".[dev]"
|
|
603
|
+
|
|
604
|
+
# Or using pip
|
|
605
|
+
pip install -e ".[dev]"
|
|
606
|
+
|
|
607
|
+
# Run tests
|
|
608
|
+
pytest
|
|
609
|
+
|
|
610
|
+
# Run linting
|
|
611
|
+
ruff check .
|
|
612
|
+
ruff format .
|
|
613
|
+
|
|
614
|
+
# Run type checking
|
|
615
|
+
mypy src/
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
## License
|
|
619
|
+
|
|
620
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
621
|
+
|
|
622
|
+
## Changelog
|
|
623
|
+
|
|
624
|
+
### 0.1.0
|
|
625
|
+
|
|
626
|
+
- Initial release
|
|
627
|
+
- Core component system
|
|
628
|
+
- Rich theming support
|
|
629
|
+
- Automatic spacing
|
|
630
|
+
- Progress tracking
|
|
631
|
+
- Interactive prompts
|