webscout 8.2.8__py3-none-any.whl → 8.3__py3-none-any.whl
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.
Potentially problematic release.
This version of webscout might be problematic. Click here for more details.
- webscout/AIauto.py +34 -16
- webscout/AIbase.py +96 -37
- webscout/AIutel.py +491 -87
- webscout/Bard.py +441 -323
- webscout/Extra/GitToolkit/__init__.py +10 -10
- webscout/Extra/YTToolkit/ytapi/video.py +232 -232
- webscout/Litlogger/README.md +10 -0
- webscout/Litlogger/__init__.py +7 -59
- webscout/Litlogger/formats.py +4 -0
- webscout/Litlogger/handlers.py +103 -0
- webscout/Litlogger/levels.py +13 -0
- webscout/Litlogger/logger.py +92 -0
- webscout/Provider/AISEARCH/Perplexity.py +332 -358
- webscout/Provider/AISEARCH/felo_search.py +9 -35
- webscout/Provider/AISEARCH/genspark_search.py +30 -56
- webscout/Provider/AISEARCH/hika_search.py +4 -16
- webscout/Provider/AISEARCH/iask_search.py +410 -436
- webscout/Provider/AISEARCH/monica_search.py +4 -30
- webscout/Provider/AISEARCH/scira_search.py +6 -32
- webscout/Provider/AISEARCH/webpilotai_search.py +38 -64
- webscout/Provider/Blackboxai.py +155 -35
- webscout/Provider/ChatSandbox.py +2 -1
- webscout/Provider/Deepinfra.py +339 -339
- webscout/Provider/ExaChat.py +358 -358
- webscout/Provider/Gemini.py +169 -169
- webscout/Provider/GithubChat.py +1 -2
- webscout/Provider/Glider.py +3 -3
- webscout/Provider/HeckAI.py +172 -82
- webscout/Provider/LambdaChat.py +1 -0
- webscout/Provider/MCPCore.py +7 -3
- webscout/Provider/OPENAI/BLACKBOXAI.py +421 -139
- webscout/Provider/OPENAI/Cloudflare.py +38 -21
- webscout/Provider/OPENAI/FalconH1.py +457 -0
- webscout/Provider/OPENAI/FreeGemini.py +35 -18
- webscout/Provider/OPENAI/NEMOTRON.py +34 -34
- webscout/Provider/OPENAI/PI.py +427 -0
- webscout/Provider/OPENAI/Qwen3.py +304 -0
- webscout/Provider/OPENAI/README.md +952 -1253
- webscout/Provider/OPENAI/TwoAI.py +374 -0
- webscout/Provider/OPENAI/__init__.py +7 -1
- webscout/Provider/OPENAI/ai4chat.py +73 -63
- webscout/Provider/OPENAI/api.py +869 -644
- webscout/Provider/OPENAI/base.py +2 -0
- webscout/Provider/OPENAI/c4ai.py +34 -13
- webscout/Provider/OPENAI/chatgpt.py +575 -556
- webscout/Provider/OPENAI/chatgptclone.py +512 -487
- webscout/Provider/OPENAI/chatsandbox.py +11 -6
- webscout/Provider/OPENAI/copilot.py +258 -0
- webscout/Provider/OPENAI/deepinfra.py +327 -318
- webscout/Provider/OPENAI/e2b.py +140 -104
- webscout/Provider/OPENAI/exaai.py +420 -411
- webscout/Provider/OPENAI/exachat.py +448 -443
- webscout/Provider/OPENAI/flowith.py +7 -3
- webscout/Provider/OPENAI/freeaichat.py +12 -8
- webscout/Provider/OPENAI/glider.py +15 -8
- webscout/Provider/OPENAI/groq.py +5 -2
- webscout/Provider/OPENAI/heckai.py +311 -307
- webscout/Provider/OPENAI/llmchatco.py +9 -7
- webscout/Provider/OPENAI/mcpcore.py +18 -9
- webscout/Provider/OPENAI/multichat.py +7 -5
- webscout/Provider/OPENAI/netwrck.py +16 -11
- webscout/Provider/OPENAI/oivscode.py +290 -0
- webscout/Provider/OPENAI/opkfc.py +507 -496
- webscout/Provider/OPENAI/pydantic_imports.py +172 -0
- webscout/Provider/OPENAI/scirachat.py +29 -17
- webscout/Provider/OPENAI/sonus.py +308 -303
- webscout/Provider/OPENAI/standardinput.py +442 -433
- webscout/Provider/OPENAI/textpollinations.py +18 -11
- webscout/Provider/OPENAI/toolbaz.py +419 -413
- webscout/Provider/OPENAI/typefully.py +17 -10
- webscout/Provider/OPENAI/typegpt.py +21 -11
- webscout/Provider/OPENAI/uncovrAI.py +477 -462
- webscout/Provider/OPENAI/utils.py +90 -79
- webscout/Provider/OPENAI/venice.py +435 -425
- webscout/Provider/OPENAI/wisecat.py +387 -381
- webscout/Provider/OPENAI/writecream.py +166 -163
- webscout/Provider/OPENAI/x0gpt.py +26 -37
- webscout/Provider/OPENAI/yep.py +384 -356
- webscout/Provider/PI.py +2 -1
- webscout/Provider/TTI/README.md +55 -101
- webscout/Provider/TTI/__init__.py +4 -9
- webscout/Provider/TTI/aiarta.py +365 -0
- webscout/Provider/TTI/artbit.py +0 -0
- webscout/Provider/TTI/base.py +64 -0
- webscout/Provider/TTI/fastflux.py +200 -0
- webscout/Provider/TTI/magicstudio.py +201 -0
- webscout/Provider/TTI/piclumen.py +203 -0
- webscout/Provider/TTI/pixelmuse.py +225 -0
- webscout/Provider/TTI/pollinations.py +221 -0
- webscout/Provider/TTI/utils.py +11 -0
- webscout/Provider/TTS/__init__.py +2 -1
- webscout/Provider/TTS/base.py +159 -159
- webscout/Provider/TTS/openai_fm.py +129 -0
- webscout/Provider/TextPollinationsAI.py +308 -308
- webscout/Provider/TwoAI.py +239 -44
- webscout/Provider/UNFINISHED/Youchat.py +330 -330
- webscout/Provider/UNFINISHED/puterjs.py +635 -0
- webscout/Provider/UNFINISHED/test_lmarena.py +119 -119
- webscout/Provider/Writecream.py +246 -246
- webscout/Provider/__init__.py +2 -2
- webscout/Provider/ai4chat.py +33 -8
- webscout/Provider/granite.py +41 -6
- webscout/Provider/koala.py +169 -169
- webscout/Provider/oivscode.py +309 -0
- webscout/Provider/samurai.py +3 -2
- webscout/Provider/scnet.py +1 -0
- webscout/Provider/typegpt.py +3 -3
- webscout/Provider/uncovr.py +368 -368
- webscout/client.py +70 -0
- webscout/litprinter/__init__.py +58 -58
- webscout/optimizers.py +419 -419
- webscout/scout/README.md +3 -1
- webscout/scout/core/crawler.py +134 -64
- webscout/scout/core/scout.py +148 -109
- webscout/scout/element.py +106 -88
- webscout/swiftcli/Readme.md +323 -323
- webscout/swiftcli/plugins/manager.py +9 -2
- webscout/version.py +1 -1
- webscout/zeroart/__init__.py +134 -134
- webscout/zeroart/effects.py +100 -100
- webscout/zeroart/fonts.py +1238 -1238
- {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/METADATA +160 -35
- webscout-8.3.dist-info/RECORD +290 -0
- {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/WHEEL +1 -1
- {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/entry_points.txt +1 -0
- webscout/Litlogger/Readme.md +0 -175
- webscout/Litlogger/core/__init__.py +0 -6
- webscout/Litlogger/core/level.py +0 -23
- webscout/Litlogger/core/logger.py +0 -165
- webscout/Litlogger/handlers/__init__.py +0 -12
- webscout/Litlogger/handlers/console.py +0 -33
- webscout/Litlogger/handlers/file.py +0 -143
- webscout/Litlogger/handlers/network.py +0 -173
- webscout/Litlogger/styles/__init__.py +0 -7
- webscout/Litlogger/styles/colors.py +0 -249
- webscout/Litlogger/styles/formats.py +0 -458
- webscout/Litlogger/styles/text.py +0 -87
- webscout/Litlogger/utils/__init__.py +0 -6
- webscout/Litlogger/utils/detectors.py +0 -153
- webscout/Litlogger/utils/formatters.py +0 -200
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/TTI/AiForce/README.md +0 -159
- webscout/Provider/TTI/AiForce/__init__.py +0 -22
- webscout/Provider/TTI/AiForce/async_aiforce.py +0 -224
- webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -245
- webscout/Provider/TTI/FreeAIPlayground/README.md +0 -99
- webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -9
- webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -181
- webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -180
- webscout/Provider/TTI/ImgSys/README.md +0 -174
- webscout/Provider/TTI/ImgSys/__init__.py +0 -23
- webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -202
- webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -195
- webscout/Provider/TTI/MagicStudio/README.md +0 -101
- webscout/Provider/TTI/MagicStudio/__init__.py +0 -2
- webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -111
- webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -109
- webscout/Provider/TTI/Nexra/README.md +0 -155
- webscout/Provider/TTI/Nexra/__init__.py +0 -22
- webscout/Provider/TTI/Nexra/async_nexra.py +0 -286
- webscout/Provider/TTI/Nexra/sync_nexra.py +0 -258
- webscout/Provider/TTI/PollinationsAI/README.md +0 -146
- webscout/Provider/TTI/PollinationsAI/__init__.py +0 -23
- webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -311
- webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -265
- webscout/Provider/TTI/aiarta/README.md +0 -134
- webscout/Provider/TTI/aiarta/__init__.py +0 -2
- webscout/Provider/TTI/aiarta/async_aiarta.py +0 -482
- webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -440
- webscout/Provider/TTI/artbit/README.md +0 -100
- webscout/Provider/TTI/artbit/__init__.py +0 -22
- webscout/Provider/TTI/artbit/async_artbit.py +0 -155
- webscout/Provider/TTI/artbit/sync_artbit.py +0 -148
- webscout/Provider/TTI/fastflux/README.md +0 -129
- webscout/Provider/TTI/fastflux/__init__.py +0 -22
- webscout/Provider/TTI/fastflux/async_fastflux.py +0 -261
- webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -252
- webscout/Provider/TTI/huggingface/README.md +0 -114
- webscout/Provider/TTI/huggingface/__init__.py +0 -22
- webscout/Provider/TTI/huggingface/async_huggingface.py +0 -199
- webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -195
- webscout/Provider/TTI/piclumen/README.md +0 -161
- webscout/Provider/TTI/piclumen/__init__.py +0 -23
- webscout/Provider/TTI/piclumen/async_piclumen.py +0 -268
- webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -233
- webscout/Provider/TTI/pixelmuse/README.md +0 -79
- webscout/Provider/TTI/pixelmuse/__init__.py +0 -4
- webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -249
- webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -182
- webscout/Provider/TTI/talkai/README.md +0 -139
- webscout/Provider/TTI/talkai/__init__.py +0 -4
- webscout/Provider/TTI/talkai/async_talkai.py +0 -229
- webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
- webscout/Provider/UNFINISHED/oivscode.py +0 -351
- webscout-8.2.8.dist-info/RECORD +0 -334
- {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/top_level.txt +0 -0
webscout/swiftcli/Readme.md
CHANGED
|
@@ -1,323 +1,323 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# ⚡ SwiftCLI
|
|
4
|
-
|
|
5
|
-
> Build Beautiful Command-Line Applications at Light Speed
|
|
6
|
-
|
|
7
|
-
[](https://www.python.org)
|
|
8
|
-
[](https://pypi.org/project/webscout/)
|
|
9
|
-
[](LICENSE)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</div>
|
|
13
|
-
|
|
14
|
-
## 🌟 Key Features
|
|
15
|
-
|
|
16
|
-
- 🎨 **Rich Output**: Beautiful tables, progress bars, and styled text
|
|
17
|
-
- 🔄 **Command Groups**: Organize commands logically
|
|
18
|
-
- 🎯 **Type Safety**: Full type hints and runtime validation
|
|
19
|
-
- 🔌 **Plugin System**: Extend functionality easily
|
|
20
|
-
- 🌍 **Environment Support**: Load config from env vars and files
|
|
21
|
-
- 🚀 **Modern Python**: Async support, type hints, and more
|
|
22
|
-
|
|
23
|
-
## 📦 Installation
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
pip install -U webscout
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## 🚀 Quick Start
|
|
30
|
-
|
|
31
|
-
```python
|
|
32
|
-
from webscout.swiftcli import CLI, option, table_output
|
|
33
|
-
|
|
34
|
-
app = CLI("myapp", version="1.0.0")
|
|
35
|
-
|
|
36
|
-
@app.command()
|
|
37
|
-
@option("--count", "-c", type=int, default=5)
|
|
38
|
-
@table_output(["ID", "Status"])
|
|
39
|
-
def list_items(count: int):
|
|
40
|
-
"""List system items with status"""
|
|
41
|
-
return [
|
|
42
|
-
[i, "Active" if i % 2 == 0 else "Inactive"]
|
|
43
|
-
for i in range(1, count + 1)
|
|
44
|
-
]
|
|
45
|
-
|
|
46
|
-
if __name__ == "__main__":
|
|
47
|
-
app.run()
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Run it:
|
|
51
|
-
```bash
|
|
52
|
-
$ python app.py list-items --count 3
|
|
53
|
-
┌────┬──────────┐
|
|
54
|
-
│ ID │ Status │
|
|
55
|
-
├────┼──────────┤
|
|
56
|
-
│ 1 │ Inactive │
|
|
57
|
-
│ 2 │ Active │
|
|
58
|
-
│ 3 │ Inactive │
|
|
59
|
-
└────┴──────────┘
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## 📚 Documentation
|
|
63
|
-
|
|
64
|
-
### Command Groups
|
|
65
|
-
|
|
66
|
-
Organize related commands:
|
|
67
|
-
|
|
68
|
-
```python
|
|
69
|
-
@app.group()
|
|
70
|
-
def db():
|
|
71
|
-
"""Database operations"""
|
|
72
|
-
pass
|
|
73
|
-
|
|
74
|
-
@db.command()
|
|
75
|
-
@option("--force", is_flag=True)
|
|
76
|
-
def migrate(force: bool):
|
|
77
|
-
"""Run database migrations"""
|
|
78
|
-
print(f"Running migrations (force={force})")
|
|
79
|
-
|
|
80
|
-
# Usage: python app.py db migrate --force
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Rich Output
|
|
84
|
-
|
|
85
|
-
Beautiful progress bars and tables:
|
|
86
|
-
|
|
87
|
-
```python
|
|
88
|
-
@app.command()
|
|
89
|
-
@progress("Processing")
|
|
90
|
-
async def process():
|
|
91
|
-
"""Process items with progress"""
|
|
92
|
-
for i in range(5):
|
|
93
|
-
yield f"Step {i+1}/5"
|
|
94
|
-
await asyncio.sleep(0.5)
|
|
95
|
-
|
|
96
|
-
@app.command()
|
|
97
|
-
@table_output(["Name", "Score"])
|
|
98
|
-
def top_scores():
|
|
99
|
-
"""Show top scores"""
|
|
100
|
-
return [
|
|
101
|
-
["Alice", 100],
|
|
102
|
-
["Bob", 95],
|
|
103
|
-
["Charlie", 90]
|
|
104
|
-
]
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Type-Safe Options
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
from enum import Enum
|
|
111
|
-
from datetime import datetime
|
|
112
|
-
from typing import List, Optional
|
|
113
|
-
|
|
114
|
-
class Format(Enum):
|
|
115
|
-
JSON = "json"
|
|
116
|
-
YAML = "yaml"
|
|
117
|
-
CSV = "csv"
|
|
118
|
-
|
|
119
|
-
@app.command()
|
|
120
|
-
@option("--format", type=Format, default=Format.JSON)
|
|
121
|
-
@option("--date", type=datetime)
|
|
122
|
-
@option("--tags", type=List[str])
|
|
123
|
-
def export(
|
|
124
|
-
format: Format,
|
|
125
|
-
date: datetime,
|
|
126
|
-
tags: Optional[List[str]] = None
|
|
127
|
-
):
|
|
128
|
-
"""Export data with type validation"""
|
|
129
|
-
print(f"Exporting as {format.value}")
|
|
130
|
-
print(f"Date: {date}")
|
|
131
|
-
if tags:
|
|
132
|
-
print(f"Tags: {', '.join(tags)}")
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Environment & Config
|
|
136
|
-
|
|
137
|
-
```python
|
|
138
|
-
@app.command()
|
|
139
|
-
@envvar("API_KEY", required=True)
|
|
140
|
-
@config_file("~/.config/myapp.yaml")
|
|
141
|
-
def api_call(api_key: str, config: dict):
|
|
142
|
-
"""Make API call using config"""
|
|
143
|
-
url = config.get("api_url")
|
|
144
|
-
print(f"Calling {url} with key {api_key[:4]}...")
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Async Support
|
|
148
|
-
|
|
149
|
-
```python
|
|
150
|
-
@app.command()
|
|
151
|
-
async def fetch_data():
|
|
152
|
-
"""Fetch data asynchronously"""
|
|
153
|
-
async with aiohttp.ClientSession() as session:
|
|
154
|
-
async with session.get("https://api.example.com") as resp:
|
|
155
|
-
data = await resp.json()
|
|
156
|
-
return data
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Plugin System
|
|
160
|
-
|
|
161
|
-
```python
|
|
162
|
-
from webscout.swiftcli import Plugin
|
|
163
|
-
|
|
164
|
-
class MetricsPlugin(Plugin):
|
|
165
|
-
def __init__(self):
|
|
166
|
-
self.start_time = None
|
|
167
|
-
|
|
168
|
-
def before_command(self, command: str, args: list):
|
|
169
|
-
self.start_time = time.time()
|
|
170
|
-
|
|
171
|
-
def after_command(self, command: str, args: list, result: any):
|
|
172
|
-
duration = time.time() - self.start_time
|
|
173
|
-
print(f"Command {command} took {duration:.2f}s")
|
|
174
|
-
|
|
175
|
-
app.plugin_manager.register(MetricsPlugin())
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## 🛠 Advanced Features
|
|
179
|
-
|
|
180
|
-
### Custom Output Formatting
|
|
181
|
-
|
|
182
|
-
```python
|
|
183
|
-
from rich.console import Console
|
|
184
|
-
from rich.panel import Panel
|
|
185
|
-
from rich.table import Table
|
|
186
|
-
|
|
187
|
-
console = Console()
|
|
188
|
-
|
|
189
|
-
@app.command()
|
|
190
|
-
def status():
|
|
191
|
-
"""Show system status"""
|
|
192
|
-
table = Table(show_header=True)
|
|
193
|
-
table.add_column("Service")
|
|
194
|
-
table.add_column("Status")
|
|
195
|
-
table.add_column("Uptime")
|
|
196
|
-
|
|
197
|
-
table.add_row("API", "✅ Online", "24h")
|
|
198
|
-
table.add_row("DB", "✅ Online", "12h")
|
|
199
|
-
table.add_row("Cache", "⚠️ Degraded", "6h")
|
|
200
|
-
|
|
201
|
-
console.print(Panel(
|
|
202
|
-
table,
|
|
203
|
-
title="System Status",
|
|
204
|
-
border_style="green"
|
|
205
|
-
))
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Command Pipelines
|
|
209
|
-
|
|
210
|
-
```python
|
|
211
|
-
@app.group(chain=True)
|
|
212
|
-
def process():
|
|
213
|
-
"""Data processing pipeline"""
|
|
214
|
-
pass
|
|
215
|
-
|
|
216
|
-
@process.command()
|
|
217
|
-
def extract():
|
|
218
|
-
"""Extract data"""
|
|
219
|
-
return {"data": [1, 2, 3]}
|
|
220
|
-
|
|
221
|
-
@process.command()
|
|
222
|
-
def transform(data: dict):
|
|
223
|
-
"""Transform data"""
|
|
224
|
-
return {"data": [x * 2 for x in data["data"]]}
|
|
225
|
-
|
|
226
|
-
@process.command()
|
|
227
|
-
def load(data: dict):
|
|
228
|
-
"""Load data"""
|
|
229
|
-
print(f"Loading: {data}")
|
|
230
|
-
|
|
231
|
-
# Usage: python app.py process extract transform load
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## 🔧 Configuration
|
|
235
|
-
|
|
236
|
-
### Application Config
|
|
237
|
-
|
|
238
|
-
```python
|
|
239
|
-
app = CLI(
|
|
240
|
-
name="myapp",
|
|
241
|
-
version="1.0.0",
|
|
242
|
-
description="My awesome CLI app",
|
|
243
|
-
config_file="~/.config/myapp.yaml",
|
|
244
|
-
auto_envvar_prefix="MYAPP",
|
|
245
|
-
plugin_folder="~/.myapp/plugins"
|
|
246
|
-
)
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### Command Config
|
|
250
|
-
|
|
251
|
-
```python
|
|
252
|
-
@app.command()
|
|
253
|
-
@option("--config", type=click.Path(exists=True))
|
|
254
|
-
@option("--verbose", "-v", count=True)
|
|
255
|
-
@option("--format", type=click.Choice(["json", "yaml"]))
|
|
256
|
-
def process(config: str, verbose: int, format: str):
|
|
257
|
-
"""Process with configuration"""
|
|
258
|
-
pass
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
## 📋 Best Practices
|
|
262
|
-
|
|
263
|
-
1. **Use Type Hints**
|
|
264
|
-
```python
|
|
265
|
-
from typing import Optional, List, Dict
|
|
266
|
-
|
|
267
|
-
@app.command()
|
|
268
|
-
def search(
|
|
269
|
-
query: str,
|
|
270
|
-
limit: Optional[int] = 10,
|
|
271
|
-
tags: List[str] = None
|
|
272
|
-
) -> Dict[str, any]:
|
|
273
|
-
"""Search with proper type hints"""
|
|
274
|
-
pass
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
2. **Structured Error Handling**
|
|
278
|
-
```python
|
|
279
|
-
from webscout.swiftcli import CLIError
|
|
280
|
-
|
|
281
|
-
@app.command()
|
|
282
|
-
def risky():
|
|
283
|
-
try:
|
|
284
|
-
# Risky operation
|
|
285
|
-
pass
|
|
286
|
-
except FileNotFoundError as e:
|
|
287
|
-
raise CLIError("Config file not found") from e
|
|
288
|
-
except PermissionError as e:
|
|
289
|
-
raise CLIError("Permission denied") from e
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
3. **Command Organization**
|
|
293
|
-
```python
|
|
294
|
-
# commands/
|
|
295
|
-
# ├── __init__.py
|
|
296
|
-
# ├── db.py
|
|
297
|
-
# ├── auth.py
|
|
298
|
-
# └── utils.py
|
|
299
|
-
|
|
300
|
-
from .commands import db, auth, utils
|
|
301
|
-
|
|
302
|
-
app.add_command_group(db.commands)
|
|
303
|
-
app.add_command_group(auth.commands)
|
|
304
|
-
app.add_command_group(utils.commands)
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
## 🤝 Contributing
|
|
308
|
-
|
|
309
|
-
Contributions are welcome! Check out our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
310
|
-
|
|
311
|
-
## 📝 License
|
|
312
|
-
|
|
313
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
314
|
-
|
|
315
|
-
<div align="center">
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
Made with ❤️ by the [Webscout](https://github.com/OEvortex/Webscout) team
|
|
320
|
-
|
|
321
|
-
[](https://github.com/OEvortex/Webscout)
|
|
322
|
-
|
|
323
|
-
</div>
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ⚡ SwiftCLI
|
|
4
|
+
|
|
5
|
+
> Build Beautiful Command-Line Applications at Light Speed
|
|
6
|
+
|
|
7
|
+
[](https://www.python.org)
|
|
8
|
+
[](https://pypi.org/project/webscout/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
## 🌟 Key Features
|
|
15
|
+
|
|
16
|
+
- 🎨 **Rich Output**: Beautiful tables, progress bars, and styled text
|
|
17
|
+
- 🔄 **Command Groups**: Organize commands logically
|
|
18
|
+
- 🎯 **Type Safety**: Full type hints and runtime validation
|
|
19
|
+
- 🔌 **Plugin System**: Extend functionality easily
|
|
20
|
+
- 🌍 **Environment Support**: Load config from env vars and files
|
|
21
|
+
- 🚀 **Modern Python**: Async support, type hints, and more
|
|
22
|
+
|
|
23
|
+
## 📦 Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install -U webscout
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🚀 Quick Start
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from webscout.swiftcli import CLI, option, table_output
|
|
33
|
+
|
|
34
|
+
app = CLI("myapp", version="1.0.0")
|
|
35
|
+
|
|
36
|
+
@app.command()
|
|
37
|
+
@option("--count", "-c", type=int, default=5)
|
|
38
|
+
@table_output(["ID", "Status"])
|
|
39
|
+
def list_items(count: int):
|
|
40
|
+
"""List system items with status"""
|
|
41
|
+
return [
|
|
42
|
+
[i, "Active" if i % 2 == 0 else "Inactive"]
|
|
43
|
+
for i in range(1, count + 1)
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
app.run()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Run it:
|
|
51
|
+
```bash
|
|
52
|
+
$ python app.py list-items --count 3
|
|
53
|
+
┌────┬──────────┐
|
|
54
|
+
│ ID │ Status │
|
|
55
|
+
├────┼──────────┤
|
|
56
|
+
│ 1 │ Inactive │
|
|
57
|
+
│ 2 │ Active │
|
|
58
|
+
│ 3 │ Inactive │
|
|
59
|
+
└────┴──────────┘
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 📚 Documentation
|
|
63
|
+
|
|
64
|
+
### Command Groups
|
|
65
|
+
|
|
66
|
+
Organize related commands:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
@app.group()
|
|
70
|
+
def db():
|
|
71
|
+
"""Database operations"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
@db.command()
|
|
75
|
+
@option("--force", is_flag=True)
|
|
76
|
+
def migrate(force: bool):
|
|
77
|
+
"""Run database migrations"""
|
|
78
|
+
print(f"Running migrations (force={force})")
|
|
79
|
+
|
|
80
|
+
# Usage: python app.py db migrate --force
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Rich Output
|
|
84
|
+
|
|
85
|
+
Beautiful progress bars and tables:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
@app.command()
|
|
89
|
+
@progress("Processing")
|
|
90
|
+
async def process():
|
|
91
|
+
"""Process items with progress"""
|
|
92
|
+
for i in range(5):
|
|
93
|
+
yield f"Step {i+1}/5"
|
|
94
|
+
await asyncio.sleep(0.5)
|
|
95
|
+
|
|
96
|
+
@app.command()
|
|
97
|
+
@table_output(["Name", "Score"])
|
|
98
|
+
def top_scores():
|
|
99
|
+
"""Show top scores"""
|
|
100
|
+
return [
|
|
101
|
+
["Alice", 100],
|
|
102
|
+
["Bob", 95],
|
|
103
|
+
["Charlie", 90]
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Type-Safe Options
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from enum import Enum
|
|
111
|
+
from datetime import datetime
|
|
112
|
+
from typing import List, Optional
|
|
113
|
+
|
|
114
|
+
class Format(Enum):
|
|
115
|
+
JSON = "json"
|
|
116
|
+
YAML = "yaml"
|
|
117
|
+
CSV = "csv"
|
|
118
|
+
|
|
119
|
+
@app.command()
|
|
120
|
+
@option("--format", type=Format, default=Format.JSON)
|
|
121
|
+
@option("--date", type=datetime)
|
|
122
|
+
@option("--tags", type=List[str])
|
|
123
|
+
def export(
|
|
124
|
+
format: Format,
|
|
125
|
+
date: datetime,
|
|
126
|
+
tags: Optional[List[str]] = None
|
|
127
|
+
):
|
|
128
|
+
"""Export data with type validation"""
|
|
129
|
+
print(f"Exporting as {format.value}")
|
|
130
|
+
print(f"Date: {date}")
|
|
131
|
+
if tags:
|
|
132
|
+
print(f"Tags: {', '.join(tags)}")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Environment & Config
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
@app.command()
|
|
139
|
+
@envvar("API_KEY", required=True)
|
|
140
|
+
@config_file("~/.config/myapp.yaml")
|
|
141
|
+
def api_call(api_key: str, config: dict):
|
|
142
|
+
"""Make API call using config"""
|
|
143
|
+
url = config.get("api_url")
|
|
144
|
+
print(f"Calling {url} with key {api_key[:4]}...")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Async Support
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
@app.command()
|
|
151
|
+
async def fetch_data():
|
|
152
|
+
"""Fetch data asynchronously"""
|
|
153
|
+
async with aiohttp.ClientSession() as session:
|
|
154
|
+
async with session.get("https://api.example.com") as resp:
|
|
155
|
+
data = await resp.json()
|
|
156
|
+
return data
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Plugin System
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from webscout.swiftcli import Plugin
|
|
163
|
+
|
|
164
|
+
class MetricsPlugin(Plugin):
|
|
165
|
+
def __init__(self):
|
|
166
|
+
self.start_time = None
|
|
167
|
+
|
|
168
|
+
def before_command(self, command: str, args: list):
|
|
169
|
+
self.start_time = time.time()
|
|
170
|
+
|
|
171
|
+
def after_command(self, command: str, args: list, result: any):
|
|
172
|
+
duration = time.time() - self.start_time
|
|
173
|
+
print(f"Command {command} took {duration:.2f}s")
|
|
174
|
+
|
|
175
|
+
app.plugin_manager.register(MetricsPlugin())
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## 🛠 Advanced Features
|
|
179
|
+
|
|
180
|
+
### Custom Output Formatting
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from rich.console import Console
|
|
184
|
+
from rich.panel import Panel
|
|
185
|
+
from rich.table import Table
|
|
186
|
+
|
|
187
|
+
console = Console()
|
|
188
|
+
|
|
189
|
+
@app.command()
|
|
190
|
+
def status():
|
|
191
|
+
"""Show system status"""
|
|
192
|
+
table = Table(show_header=True)
|
|
193
|
+
table.add_column("Service")
|
|
194
|
+
table.add_column("Status")
|
|
195
|
+
table.add_column("Uptime")
|
|
196
|
+
|
|
197
|
+
table.add_row("API", "✅ Online", "24h")
|
|
198
|
+
table.add_row("DB", "✅ Online", "12h")
|
|
199
|
+
table.add_row("Cache", "⚠️ Degraded", "6h")
|
|
200
|
+
|
|
201
|
+
console.print(Panel(
|
|
202
|
+
table,
|
|
203
|
+
title="System Status",
|
|
204
|
+
border_style="green"
|
|
205
|
+
))
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Command Pipelines
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
@app.group(chain=True)
|
|
212
|
+
def process():
|
|
213
|
+
"""Data processing pipeline"""
|
|
214
|
+
pass
|
|
215
|
+
|
|
216
|
+
@process.command()
|
|
217
|
+
def extract():
|
|
218
|
+
"""Extract data"""
|
|
219
|
+
return {"data": [1, 2, 3]}
|
|
220
|
+
|
|
221
|
+
@process.command()
|
|
222
|
+
def transform(data: dict):
|
|
223
|
+
"""Transform data"""
|
|
224
|
+
return {"data": [x * 2 for x in data["data"]]}
|
|
225
|
+
|
|
226
|
+
@process.command()
|
|
227
|
+
def load(data: dict):
|
|
228
|
+
"""Load data"""
|
|
229
|
+
print(f"Loading: {data}")
|
|
230
|
+
|
|
231
|
+
# Usage: python app.py process extract transform load
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 🔧 Configuration
|
|
235
|
+
|
|
236
|
+
### Application Config
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
app = CLI(
|
|
240
|
+
name="myapp",
|
|
241
|
+
version="1.0.0",
|
|
242
|
+
description="My awesome CLI app",
|
|
243
|
+
config_file="~/.config/myapp.yaml",
|
|
244
|
+
auto_envvar_prefix="MYAPP",
|
|
245
|
+
plugin_folder="~/.myapp/plugins"
|
|
246
|
+
)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Command Config
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
@app.command()
|
|
253
|
+
@option("--config", type=click.Path(exists=True))
|
|
254
|
+
@option("--verbose", "-v", count=True)
|
|
255
|
+
@option("--format", type=click.Choice(["json", "yaml"]))
|
|
256
|
+
def process(config: str, verbose: int, format: str):
|
|
257
|
+
"""Process with configuration"""
|
|
258
|
+
pass
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## 📋 Best Practices
|
|
262
|
+
|
|
263
|
+
1. **Use Type Hints**
|
|
264
|
+
```python
|
|
265
|
+
from typing import Optional, List, Dict
|
|
266
|
+
|
|
267
|
+
@app.command()
|
|
268
|
+
def search(
|
|
269
|
+
query: str,
|
|
270
|
+
limit: Optional[int] = 10,
|
|
271
|
+
tags: List[str] = None
|
|
272
|
+
) -> Dict[str, any]:
|
|
273
|
+
"""Search with proper type hints"""
|
|
274
|
+
pass
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
2. **Structured Error Handling**
|
|
278
|
+
```python
|
|
279
|
+
from webscout.swiftcli import CLIError
|
|
280
|
+
|
|
281
|
+
@app.command()
|
|
282
|
+
def risky():
|
|
283
|
+
try:
|
|
284
|
+
# Risky operation
|
|
285
|
+
pass
|
|
286
|
+
except FileNotFoundError as e:
|
|
287
|
+
raise CLIError("Config file not found") from e
|
|
288
|
+
except PermissionError as e:
|
|
289
|
+
raise CLIError("Permission denied") from e
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
3. **Command Organization**
|
|
293
|
+
```python
|
|
294
|
+
# commands/
|
|
295
|
+
# ├── __init__.py
|
|
296
|
+
# ├── db.py
|
|
297
|
+
# ├── auth.py
|
|
298
|
+
# └── utils.py
|
|
299
|
+
|
|
300
|
+
from .commands import db, auth, utils
|
|
301
|
+
|
|
302
|
+
app.add_command_group(db.commands)
|
|
303
|
+
app.add_command_group(auth.commands)
|
|
304
|
+
app.add_command_group(utils.commands)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## 🤝 Contributing
|
|
308
|
+
|
|
309
|
+
Contributions are welcome! Check out our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
310
|
+
|
|
311
|
+
## 📝 License
|
|
312
|
+
|
|
313
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
314
|
+
|
|
315
|
+
<div align="center">
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
Made with ❤️ by the [Webscout](https://github.com/OEvortex/Webscout) team
|
|
320
|
+
|
|
321
|
+
[](https://github.com/OEvortex/Webscout)
|
|
322
|
+
|
|
323
|
+
</div>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import importlib
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
|
+
import tempfile
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Any, Dict, List, Optional, Type
|
|
8
9
|
|
|
@@ -42,8 +43,14 @@ class PluginManager:
|
|
|
42
43
|
plugin_dir: Optional custom plugin directory path
|
|
43
44
|
"""
|
|
44
45
|
self.plugins: List[Plugin] = []
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
# Use temporary directory instead of ~/.swiftcli/plugins
|
|
47
|
+
if plugin_dir:
|
|
48
|
+
self.plugin_dir = plugin_dir
|
|
49
|
+
os.makedirs(self.plugin_dir, exist_ok=True)
|
|
50
|
+
else:
|
|
51
|
+
# Create a temporary directory that will be cleaned up when the process exits
|
|
52
|
+
self.temp_dir = tempfile.TemporaryDirectory(prefix="swiftcli_")
|
|
53
|
+
self.plugin_dir = self.temp_dir.name
|
|
47
54
|
|
|
48
55
|
# Add plugin directory to Python path
|
|
49
56
|
if self.plugin_dir not in sys.path:
|
webscout/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version__ = "8.
|
|
1
|
+
__version__ = "8.3"
|
|
2
2
|
__prog__ = "webscout"
|