webscout 8.2.2__py3-none-any.whl → 2026.1.19__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.
- webscout/AIauto.py +524 -143
- webscout/AIbase.py +247 -123
- webscout/AIutel.py +68 -132
- webscout/Bard.py +1072 -535
- webscout/Extra/GitToolkit/__init__.py +2 -2
- webscout/Extra/GitToolkit/gitapi/__init__.py +20 -12
- webscout/Extra/GitToolkit/gitapi/gist.py +142 -0
- webscout/Extra/GitToolkit/gitapi/organization.py +91 -0
- webscout/Extra/GitToolkit/gitapi/repository.py +308 -195
- webscout/Extra/GitToolkit/gitapi/search.py +162 -0
- webscout/Extra/GitToolkit/gitapi/trending.py +236 -0
- webscout/Extra/GitToolkit/gitapi/user.py +128 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +82 -62
- webscout/Extra/YTToolkit/README.md +443 -0
- webscout/Extra/YTToolkit/YTdownloader.py +953 -957
- webscout/Extra/YTToolkit/__init__.py +3 -3
- webscout/Extra/YTToolkit/transcriber.py +595 -476
- webscout/Extra/YTToolkit/ytapi/README.md +230 -0
- webscout/Extra/YTToolkit/ytapi/__init__.py +22 -6
- webscout/Extra/YTToolkit/ytapi/captions.py +190 -0
- webscout/Extra/YTToolkit/ytapi/channel.py +302 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +178 -45
- webscout/Extra/YTToolkit/ytapi/hashtag.py +120 -0
- webscout/Extra/YTToolkit/ytapi/https.py +89 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +59 -59
- webscout/Extra/YTToolkit/ytapi/pool.py +8 -8
- webscout/Extra/YTToolkit/ytapi/query.py +143 -40
- webscout/Extra/YTToolkit/ytapi/shorts.py +122 -0
- webscout/Extra/YTToolkit/ytapi/stream.py +68 -63
- webscout/Extra/YTToolkit/ytapi/suggestions.py +97 -0
- webscout/Extra/YTToolkit/ytapi/utils.py +66 -62
- webscout/Extra/YTToolkit/ytapi/video.py +189 -18
- webscout/Extra/__init__.py +2 -3
- webscout/Extra/gguf.py +1298 -682
- webscout/Extra/tempmail/README.md +488 -0
- webscout/Extra/tempmail/__init__.py +28 -28
- webscout/Extra/tempmail/async_utils.py +143 -141
- webscout/Extra/tempmail/base.py +172 -161
- webscout/Extra/tempmail/cli.py +191 -187
- webscout/Extra/tempmail/emailnator.py +88 -84
- webscout/Extra/tempmail/mail_tm.py +378 -361
- webscout/Extra/tempmail/temp_mail_io.py +304 -292
- webscout/Extra/weather.py +196 -194
- webscout/Extra/weather_ascii.py +17 -15
- webscout/Provider/AISEARCH/PERPLEXED_search.py +175 -0
- webscout/Provider/AISEARCH/Perplexity.py +237 -304
- webscout/Provider/AISEARCH/README.md +106 -0
- webscout/Provider/AISEARCH/__init__.py +16 -10
- webscout/Provider/AISEARCH/brave_search.py +298 -0
- webscout/Provider/AISEARCH/iask_search.py +130 -209
- webscout/Provider/AISEARCH/monica_search.py +200 -246
- webscout/Provider/AISEARCH/webpilotai_search.py +242 -281
- webscout/Provider/Algion.py +413 -0
- webscout/Provider/Andi.py +74 -69
- webscout/Provider/Apriel.py +313 -0
- webscout/Provider/Ayle.py +323 -0
- webscout/Provider/ChatSandbox.py +329 -0
- webscout/Provider/ClaudeOnline.py +365 -0
- webscout/Provider/Cohere.py +232 -208
- webscout/Provider/DeepAI.py +367 -0
- webscout/Provider/Deepinfra.py +343 -173
- webscout/Provider/EssentialAI.py +217 -0
- webscout/Provider/ExaAI.py +274 -261
- webscout/Provider/Gemini.py +60 -54
- webscout/Provider/GithubChat.py +385 -367
- webscout/Provider/Gradient.py +286 -0
- webscout/Provider/Groq.py +556 -670
- webscout/Provider/HadadXYZ.py +323 -0
- webscout/Provider/HeckAI.py +392 -233
- webscout/Provider/HuggingFace.py +387 -0
- webscout/Provider/IBM.py +340 -0
- webscout/Provider/Jadve.py +317 -266
- webscout/Provider/K2Think.py +306 -0
- webscout/Provider/Koboldai.py +221 -381
- webscout/Provider/Netwrck.py +273 -228
- webscout/Provider/Nvidia.py +310 -0
- webscout/Provider/OPENAI/DeepAI.py +489 -0
- webscout/Provider/OPENAI/K2Think.py +423 -0
- webscout/Provider/OPENAI/PI.py +463 -0
- webscout/Provider/OPENAI/README.md +890 -0
- webscout/Provider/OPENAI/TogetherAI.py +405 -0
- webscout/Provider/OPENAI/TwoAI.py +255 -0
- webscout/Provider/OPENAI/__init__.py +148 -25
- webscout/Provider/OPENAI/ai4chat.py +348 -0
- webscout/Provider/OPENAI/akashgpt.py +436 -0
- webscout/Provider/OPENAI/algion.py +303 -0
- webscout/Provider/OPENAI/ayle.py +365 -0
- webscout/Provider/OPENAI/base.py +253 -46
- webscout/Provider/OPENAI/cerebras.py +296 -0
- webscout/Provider/OPENAI/chatgpt.py +514 -193
- webscout/Provider/OPENAI/chatsandbox.py +233 -0
- webscout/Provider/OPENAI/deepinfra.py +403 -272
- webscout/Provider/OPENAI/e2b.py +2370 -1350
- webscout/Provider/OPENAI/elmo.py +278 -0
- webscout/Provider/OPENAI/exaai.py +186 -138
- webscout/Provider/OPENAI/freeassist.py +446 -0
- webscout/Provider/OPENAI/gradient.py +448 -0
- webscout/Provider/OPENAI/groq.py +380 -0
- webscout/Provider/OPENAI/hadadxyz.py +292 -0
- webscout/Provider/OPENAI/heckai.py +100 -104
- webscout/Provider/OPENAI/huggingface.py +321 -0
- webscout/Provider/OPENAI/ibm.py +425 -0
- webscout/Provider/OPENAI/llmchat.py +253 -0
- webscout/Provider/OPENAI/llmchatco.py +378 -327
- webscout/Provider/OPENAI/meta.py +541 -0
- webscout/Provider/OPENAI/netwrck.py +110 -84
- webscout/Provider/OPENAI/nvidia.py +317 -0
- webscout/Provider/OPENAI/oivscode.py +348 -0
- webscout/Provider/OPENAI/openrouter.py +328 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -0
- webscout/Provider/OPENAI/sambanova.py +397 -0
- webscout/Provider/OPENAI/sonus.py +126 -115
- webscout/Provider/OPENAI/textpollinations.py +218 -133
- webscout/Provider/OPENAI/toolbaz.py +136 -166
- webscout/Provider/OPENAI/typefully.py +419 -0
- webscout/Provider/OPENAI/typliai.py +279 -0
- webscout/Provider/OPENAI/utils.py +314 -211
- webscout/Provider/OPENAI/wisecat.py +103 -125
- webscout/Provider/OPENAI/writecream.py +185 -156
- webscout/Provider/OPENAI/x0gpt.py +227 -136
- webscout/Provider/OPENAI/zenmux.py +380 -0
- webscout/Provider/OpenRouter.py +386 -0
- webscout/Provider/Openai.py +337 -496
- webscout/Provider/PI.py +443 -344
- webscout/Provider/QwenLM.py +346 -254
- webscout/Provider/STT/__init__.py +28 -0
- webscout/Provider/STT/base.py +303 -0
- webscout/Provider/STT/elevenlabs.py +264 -0
- webscout/Provider/Sambanova.py +317 -0
- webscout/Provider/TTI/README.md +69 -0
- webscout/Provider/TTI/__init__.py +37 -12
- webscout/Provider/TTI/base.py +147 -0
- webscout/Provider/TTI/claudeonline.py +393 -0
- webscout/Provider/TTI/magicstudio.py +292 -0
- webscout/Provider/TTI/miragic.py +180 -0
- webscout/Provider/TTI/pollinations.py +331 -0
- webscout/Provider/TTI/together.py +334 -0
- webscout/Provider/TTI/utils.py +14 -0
- webscout/Provider/TTS/README.md +186 -0
- webscout/Provider/TTS/__init__.py +43 -7
- webscout/Provider/TTS/base.py +523 -0
- webscout/Provider/TTS/deepgram.py +286 -156
- webscout/Provider/TTS/elevenlabs.py +189 -111
- webscout/Provider/TTS/freetts.py +218 -0
- webscout/Provider/TTS/murfai.py +288 -113
- webscout/Provider/TTS/openai_fm.py +364 -0
- webscout/Provider/TTS/parler.py +203 -111
- webscout/Provider/TTS/qwen.py +334 -0
- webscout/Provider/TTS/sherpa.py +286 -0
- webscout/Provider/TTS/speechma.py +693 -180
- webscout/Provider/TTS/streamElements.py +275 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TextPollinationsAI.py +221 -121
- webscout/Provider/TogetherAI.py +450 -0
- webscout/Provider/TwoAI.py +309 -199
- webscout/Provider/TypliAI.py +311 -0
- webscout/Provider/UNFINISHED/ChatHub.py +219 -0
- webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +160 -145
- webscout/Provider/UNFINISHED/GizAI.py +300 -0
- webscout/Provider/UNFINISHED/Marcus.py +218 -0
- webscout/Provider/UNFINISHED/Qodo.py +481 -0
- webscout/Provider/UNFINISHED/XenAI.py +330 -0
- webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +64 -47
- webscout/Provider/UNFINISHED/aihumanizer.py +41 -0
- webscout/Provider/UNFINISHED/grammerchecker.py +37 -0
- webscout/Provider/UNFINISHED/liner.py +342 -0
- webscout/Provider/UNFINISHED/liner_api_request.py +246 -0
- webscout/Provider/UNFINISHED/samurai.py +231 -0
- webscout/Provider/WiseCat.py +256 -196
- webscout/Provider/WrDoChat.py +390 -0
- webscout/Provider/__init__.py +115 -198
- webscout/Provider/ai4chat.py +181 -202
- webscout/Provider/akashgpt.py +330 -342
- webscout/Provider/cerebras.py +397 -242
- webscout/Provider/cleeai.py +236 -213
- webscout/Provider/elmo.py +291 -234
- webscout/Provider/geminiapi.py +343 -208
- webscout/Provider/julius.py +245 -223
- webscout/Provider/learnfastai.py +333 -266
- webscout/Provider/llama3mitril.py +230 -180
- webscout/Provider/llmchat.py +308 -213
- webscout/Provider/llmchatco.py +321 -311
- webscout/Provider/meta.py +996 -794
- webscout/Provider/oivscode.py +332 -0
- webscout/Provider/searchchat.py +316 -293
- webscout/Provider/sonus.py +264 -208
- webscout/Provider/toolbaz.py +359 -320
- webscout/Provider/turboseek.py +332 -219
- webscout/Provider/typefully.py +262 -280
- webscout/Provider/x0gpt.py +332 -256
- webscout/__init__.py +31 -38
- webscout/__main__.py +5 -5
- webscout/cli.py +585 -293
- webscout/client.py +1497 -0
- webscout/conversation.py +140 -565
- webscout/exceptions.py +383 -339
- webscout/litagent/__init__.py +29 -29
- webscout/litagent/agent.py +492 -455
- webscout/litagent/constants.py +60 -60
- webscout/models.py +505 -181
- webscout/optimizers.py +32 -378
- webscout/prompt_manager.py +376 -274
- webscout/sanitize.py +1514 -0
- webscout/scout/README.md +452 -0
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +7 -7
- webscout/scout/core/crawler.py +330 -140
- webscout/scout/core/scout.py +800 -568
- webscout/scout/core/search_result.py +51 -96
- webscout/scout/core/text_analyzer.py +64 -63
- webscout/scout/core/text_utils.py +412 -277
- webscout/scout/core/web_analyzer.py +54 -52
- webscout/scout/element.py +872 -460
- webscout/scout/parsers/__init__.py +70 -69
- webscout/scout/parsers/html5lib_parser.py +182 -172
- webscout/scout/parsers/html_parser.py +238 -236
- webscout/scout/parsers/lxml_parser.py +203 -178
- webscout/scout/utils.py +38 -37
- webscout/search/__init__.py +47 -0
- webscout/search/base.py +201 -0
- webscout/search/bing_main.py +45 -0
- webscout/search/brave_main.py +92 -0
- webscout/search/duckduckgo_main.py +57 -0
- webscout/search/engines/__init__.py +127 -0
- webscout/search/engines/bing/__init__.py +15 -0
- webscout/search/engines/bing/base.py +35 -0
- webscout/search/engines/bing/images.py +114 -0
- webscout/search/engines/bing/news.py +96 -0
- webscout/search/engines/bing/suggestions.py +36 -0
- webscout/search/engines/bing/text.py +109 -0
- webscout/search/engines/brave/__init__.py +19 -0
- webscout/search/engines/brave/base.py +47 -0
- webscout/search/engines/brave/images.py +213 -0
- webscout/search/engines/brave/news.py +353 -0
- webscout/search/engines/brave/suggestions.py +318 -0
- webscout/search/engines/brave/text.py +167 -0
- webscout/search/engines/brave/videos.py +364 -0
- webscout/search/engines/duckduckgo/__init__.py +25 -0
- webscout/search/engines/duckduckgo/answers.py +80 -0
- webscout/search/engines/duckduckgo/base.py +189 -0
- webscout/search/engines/duckduckgo/images.py +100 -0
- webscout/search/engines/duckduckgo/maps.py +183 -0
- webscout/search/engines/duckduckgo/news.py +70 -0
- webscout/search/engines/duckduckgo/suggestions.py +22 -0
- webscout/search/engines/duckduckgo/text.py +221 -0
- webscout/search/engines/duckduckgo/translate.py +48 -0
- webscout/search/engines/duckduckgo/videos.py +80 -0
- webscout/search/engines/duckduckgo/weather.py +84 -0
- webscout/search/engines/mojeek.py +61 -0
- webscout/search/engines/wikipedia.py +77 -0
- webscout/search/engines/yahoo/__init__.py +41 -0
- webscout/search/engines/yahoo/answers.py +19 -0
- webscout/search/engines/yahoo/base.py +34 -0
- webscout/search/engines/yahoo/images.py +323 -0
- webscout/search/engines/yahoo/maps.py +19 -0
- webscout/search/engines/yahoo/news.py +258 -0
- webscout/search/engines/yahoo/suggestions.py +140 -0
- webscout/search/engines/yahoo/text.py +273 -0
- webscout/search/engines/yahoo/translate.py +19 -0
- webscout/search/engines/yahoo/videos.py +302 -0
- webscout/search/engines/yahoo/weather.py +220 -0
- webscout/search/engines/yandex.py +67 -0
- webscout/search/engines/yep/__init__.py +13 -0
- webscout/search/engines/yep/base.py +34 -0
- webscout/search/engines/yep/images.py +101 -0
- webscout/search/engines/yep/suggestions.py +38 -0
- webscout/search/engines/yep/text.py +99 -0
- webscout/search/http_client.py +172 -0
- webscout/search/results.py +141 -0
- webscout/search/yahoo_main.py +57 -0
- webscout/search/yep_main.py +48 -0
- webscout/server/__init__.py +48 -0
- webscout/server/config.py +78 -0
- webscout/server/exceptions.py +69 -0
- webscout/server/providers.py +286 -0
- webscout/server/request_models.py +131 -0
- webscout/server/request_processing.py +404 -0
- webscout/server/routes.py +642 -0
- webscout/server/server.py +351 -0
- webscout/server/ui_templates.py +1171 -0
- webscout/swiftcli/__init__.py +79 -809
- webscout/swiftcli/core/__init__.py +7 -0
- webscout/swiftcli/core/cli.py +574 -0
- webscout/swiftcli/core/context.py +98 -0
- webscout/swiftcli/core/group.py +268 -0
- webscout/swiftcli/decorators/__init__.py +28 -0
- webscout/swiftcli/decorators/command.py +243 -0
- webscout/swiftcli/decorators/options.py +247 -0
- webscout/swiftcli/decorators/output.py +392 -0
- webscout/swiftcli/exceptions.py +21 -0
- webscout/swiftcli/plugins/__init__.py +9 -0
- webscout/swiftcli/plugins/base.py +134 -0
- webscout/swiftcli/plugins/manager.py +269 -0
- webscout/swiftcli/utils/__init__.py +58 -0
- webscout/swiftcli/utils/formatting.py +251 -0
- webscout/swiftcli/utils/parsing.py +368 -0
- webscout/update_checker.py +280 -136
- webscout/utils.py +28 -14
- webscout/version.py +2 -1
- webscout/version.py.bak +3 -0
- webscout/zeroart/__init__.py +218 -55
- webscout/zeroart/base.py +70 -60
- webscout/zeroart/effects.py +155 -99
- webscout/zeroart/fonts.py +1799 -816
- webscout-2026.1.19.dist-info/METADATA +638 -0
- webscout-2026.1.19.dist-info/RECORD +312 -0
- {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
- webscout-2026.1.19.dist-info/entry_points.txt +4 -0
- webscout-2026.1.19.dist-info/top_level.txt +1 -0
- inferno/__init__.py +0 -6
- inferno/__main__.py +0 -9
- inferno/cli.py +0 -6
- webscout/DWEBS.py +0 -477
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -849
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/LLM.py +0 -442
- webscout/Litlogger/__init__.py +0 -67
- 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/Local/__init__.py +0 -12
- webscout/Local/__main__.py +0 -9
- webscout/Local/api.py +0 -576
- webscout/Local/cli.py +0 -516
- webscout/Local/config.py +0 -75
- webscout/Local/llm.py +0 -287
- webscout/Local/model_manager.py +0 -253
- webscout/Local/server.py +0 -721
- webscout/Local/utils.py +0 -93
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -250
- webscout/Provider/AISEARCH/ISou.py +0 -256
- webscout/Provider/AISEARCH/felo_search.py +0 -228
- webscout/Provider/AISEARCH/genspark_search.py +0 -208
- webscout/Provider/AISEARCH/hika_search.py +0 -194
- webscout/Provider/AISEARCH/scira_search.py +0 -324
- webscout/Provider/Aitopia.py +0 -292
- webscout/Provider/AllenAI.py +0 -413
- webscout/Provider/Blackboxai.py +0 -229
- webscout/Provider/C4ai.py +0 -432
- webscout/Provider/ChatGPTClone.py +0 -226
- webscout/Provider/ChatGPTES.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/Chatify.py +0 -175
- webscout/Provider/Cloudflare.py +0 -273
- webscout/Provider/DeepSeek.py +0 -196
- webscout/Provider/ElectronHub.py +0 -709
- webscout/Provider/ExaChat.py +0 -342
- webscout/Provider/Free2GPT.py +0 -241
- webscout/Provider/GPTWeb.py +0 -193
- webscout/Provider/Glider.py +0 -211
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HuggingFaceChat.py +0 -462
- webscout/Provider/Hunyuan.py +0 -272
- webscout/Provider/LambdaChat.py +0 -392
- webscout/Provider/Llama.py +0 -200
- webscout/Provider/Llama3.py +0 -204
- webscout/Provider/Marcus.py +0 -148
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/c4ai.py +0 -367
- webscout/Provider/OPENAI/chatgptclone.py +0 -460
- webscout/Provider/OPENAI/exachat.py +0 -433
- webscout/Provider/OPENAI/freeaichat.py +0 -352
- webscout/Provider/OPENAI/opkfc.py +0 -488
- webscout/Provider/OPENAI/scirachat.py +0 -463
- webscout/Provider/OPENAI/standardinput.py +0 -425
- webscout/Provider/OPENAI/typegpt.py +0 -346
- webscout/Provider/OPENAI/uncovrAI.py +0 -455
- webscout/Provider/OPENAI/venice.py +0 -413
- webscout/Provider/OPENAI/yep.py +0 -327
- webscout/Provider/OpenGPT.py +0 -199
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/Phind.py +0 -535
- webscout/Provider/PizzaGPT.py +0 -198
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -278
- 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/__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/__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/__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/__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/__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/__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/__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/__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/__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/__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/__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/__init__.py +0 -4
- webscout/Provider/TTI/talkai/async_talkai.py +0 -229
- webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
- webscout/Provider/TTS/gesserit.py +0 -127
- webscout/Provider/TeachAnything.py +0 -187
- webscout/Provider/Venice.py +0 -219
- webscout/Provider/VercelAI.py +0 -234
- webscout/Provider/WebSim.py +0 -228
- webscout/Provider/Writecream.py +0 -211
- webscout/Provider/WritingMate.py +0 -197
- webscout/Provider/aimathgpt.py +0 -189
- webscout/Provider/askmyai.py +0 -158
- webscout/Provider/asksteve.py +0 -203
- webscout/Provider/bagoodex.py +0 -145
- webscout/Provider/chatglm.py +0 -205
- webscout/Provider/copilot.py +0 -428
- webscout/Provider/freeaichat.py +0 -271
- webscout/Provider/gaurish.py +0 -244
- webscout/Provider/geminiprorealtime.py +0 -160
- webscout/Provider/granite.py +0 -187
- webscout/Provider/hermes.py +0 -219
- webscout/Provider/koala.py +0 -268
- webscout/Provider/labyrinth.py +0 -340
- webscout/Provider/lepton.py +0 -194
- webscout/Provider/llamatutor.py +0 -192
- webscout/Provider/multichat.py +0 -325
- webscout/Provider/promptrefine.py +0 -193
- webscout/Provider/scira_chat.py +0 -277
- webscout/Provider/scnet.py +0 -187
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/tutorai.py +0 -252
- webscout/Provider/typegpt.py +0 -232
- webscout/Provider/uncovr.py +0 -312
- webscout/Provider/yep.py +0 -376
- webscout/litprinter/__init__.py +0 -59
- webscout/scout/core.py +0 -881
- webscout/tempid.py +0 -128
- webscout/webscout_search.py +0 -1346
- webscout/webscout_search_async.py +0 -877
- webscout/yep_search.py +0 -297
- webscout-8.2.2.dist-info/METADATA +0 -734
- webscout-8.2.2.dist-info/RECORD +0 -309
- webscout-8.2.2.dist-info/entry_points.txt +0 -5
- webscout-8.2.2.dist-info/top_level.txt +0 -3
- webstoken/__init__.py +0 -30
- webstoken/classifier.py +0 -189
- webstoken/keywords.py +0 -216
- webstoken/language.py +0 -128
- webstoken/ner.py +0 -164
- webstoken/normalizer.py +0 -35
- webstoken/processor.py +0 -77
- webstoken/sentiment.py +0 -206
- webstoken/stemmer.py +0 -73
- webstoken/tagger.py +0 -60
- webstoken/tokenizer.py +0 -158
- {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info/licenses}/LICENSE.md +0 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""Option decorators for SwiftCLI."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
# Sentinel for unspecified defaults
|
|
6
|
+
_NO_DEFAULT = object()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def option(
|
|
10
|
+
*param_decls: str,
|
|
11
|
+
type: Any = str,
|
|
12
|
+
required: bool = False,
|
|
13
|
+
default: Any = _NO_DEFAULT,
|
|
14
|
+
help: Optional[str] = None,
|
|
15
|
+
is_flag: bool = False,
|
|
16
|
+
multiple: bool = False,
|
|
17
|
+
count: bool = False,
|
|
18
|
+
prompt: Union[bool, str] = False,
|
|
19
|
+
hide_input: bool = False,
|
|
20
|
+
confirmation_prompt: Union[bool, str] = False,
|
|
21
|
+
prompt_required: bool = True,
|
|
22
|
+
show_default: bool = True,
|
|
23
|
+
choices: Optional[List[Any]] = None,
|
|
24
|
+
case_sensitive: bool = True,
|
|
25
|
+
callback: Optional[Callable] = None,
|
|
26
|
+
hidden: bool = False,
|
|
27
|
+
validation: Optional[Dict[str, Any]] = None,
|
|
28
|
+
mutually_exclusive: Optional[List[str]] = None,
|
|
29
|
+
) -> Callable:
|
|
30
|
+
"""
|
|
31
|
+
Decorator to add an option to a command.
|
|
32
|
+
|
|
33
|
+
Options are named parameters that can be provided in any order.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
param_decls: Option names (e.g., "--name", "-n")
|
|
37
|
+
type: Expected type
|
|
38
|
+
required: Whether option is required
|
|
39
|
+
default: Default value
|
|
40
|
+
help: Help text
|
|
41
|
+
is_flag: Whether option is a boolean flag
|
|
42
|
+
multiple: Whether option can be specified multiple times
|
|
43
|
+
count: Whether option counts occurrences
|
|
44
|
+
prompt: Whether to prompt for value if not provided (can be string for prompt text)
|
|
45
|
+
hide_input: Whether to hide input when prompting
|
|
46
|
+
confirmation_prompt: Whether to prompt for confirmation (can be string for prompt text)
|
|
47
|
+
prompt_required: Whether prompt is required
|
|
48
|
+
show_default: Whether to show default in help
|
|
49
|
+
choices: List of valid choices
|
|
50
|
+
case_sensitive: Whether choices are case sensitive
|
|
51
|
+
callback: Function to process/validate value
|
|
52
|
+
hidden: Whether to hide from help output
|
|
53
|
+
validation: Dictionary of validation rules (min_length, max_length, pattern, etc.)
|
|
54
|
+
mutually_exclusive: List of option names that are mutually exclusive with this option
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
@command()
|
|
58
|
+
@option("--count", "-c", type=int, default=1)
|
|
59
|
+
@option("--format", type=str, choices=["json", "yaml"])
|
|
60
|
+
@option("--verbose", is_flag=True)
|
|
61
|
+
@option("--name", validation={'min_length': 3, 'max_length': 20})
|
|
62
|
+
def process(count: int, format: str, verbose: bool, name: str):
|
|
63
|
+
'''Process data'''
|
|
64
|
+
if verbose:
|
|
65
|
+
print(f"Processing {count} items as {format}")
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def decorator(f: Callable) -> Callable:
|
|
69
|
+
if not hasattr(f, "_options"):
|
|
70
|
+
f._options = [] # type: ignore[attr-defined]
|
|
71
|
+
|
|
72
|
+
f._options.append( # type: ignore[attr-defined]
|
|
73
|
+
{
|
|
74
|
+
"param_decls": param_decls,
|
|
75
|
+
"type": type,
|
|
76
|
+
"required": required,
|
|
77
|
+
# Only include default explicitly if something other than sentinel was provided
|
|
78
|
+
**({"default": default} if default is not _NO_DEFAULT else {}),
|
|
79
|
+
"help": help,
|
|
80
|
+
"is_flag": is_flag,
|
|
81
|
+
"multiple": multiple,
|
|
82
|
+
"count": count,
|
|
83
|
+
"prompt": prompt,
|
|
84
|
+
"hide_input": hide_input,
|
|
85
|
+
"confirmation_prompt": confirmation_prompt,
|
|
86
|
+
"prompt_required": prompt_required,
|
|
87
|
+
"show_default": show_default,
|
|
88
|
+
"choices": choices,
|
|
89
|
+
"case_sensitive": case_sensitive,
|
|
90
|
+
"callback": callback,
|
|
91
|
+
"hidden": hidden,
|
|
92
|
+
"validation": validation,
|
|
93
|
+
"mutually_exclusive": mutually_exclusive,
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
return f
|
|
97
|
+
|
|
98
|
+
return decorator
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def envvar(
|
|
102
|
+
name: str,
|
|
103
|
+
type: Any = str,
|
|
104
|
+
required: bool = False,
|
|
105
|
+
default: Any = None,
|
|
106
|
+
help: Optional[str] = None,
|
|
107
|
+
) -> Callable:
|
|
108
|
+
"""
|
|
109
|
+
Decorator to load option value from environment variable.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
name: Environment variable name
|
|
113
|
+
type: Expected type
|
|
114
|
+
required: Whether variable is required
|
|
115
|
+
default: Default value if not set
|
|
116
|
+
help: Help text
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
@command()
|
|
120
|
+
@envvar("API_KEY", required=True)
|
|
121
|
+
@envvar("API_URL", default="https://api.example.com")
|
|
122
|
+
def api_call(api_key: str, api_url: str):
|
|
123
|
+
'''Make API call'''
|
|
124
|
+
print(f"Calling {api_url} with key {api_key}")
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
def decorator(f: Callable) -> Callable:
|
|
128
|
+
if not hasattr(f, "_envvars"):
|
|
129
|
+
f._envvars = [] # type: ignore[attr-defined]
|
|
130
|
+
|
|
131
|
+
f._envvars.append( # type: ignore[attr-defined]
|
|
132
|
+
{
|
|
133
|
+
"name": name,
|
|
134
|
+
"type": type,
|
|
135
|
+
"required": required,
|
|
136
|
+
"default": default,
|
|
137
|
+
"help": help,
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
return f
|
|
141
|
+
|
|
142
|
+
return decorator
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def config_file(
|
|
146
|
+
path: Optional[str] = None,
|
|
147
|
+
section: Optional[str] = None,
|
|
148
|
+
required: bool = False,
|
|
149
|
+
auto_create: bool = True,
|
|
150
|
+
format: str = "json",
|
|
151
|
+
) -> Callable:
|
|
152
|
+
"""
|
|
153
|
+
Decorator to load configuration from file.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
path: Config file path
|
|
157
|
+
section: Config section to load
|
|
158
|
+
required: Whether config is required
|
|
159
|
+
auto_create: Whether to create file if missing
|
|
160
|
+
format: File format (json, yaml, ini)
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
@command()
|
|
164
|
+
@config_file("~/.myapp/config.json")
|
|
165
|
+
def setup(config: dict):
|
|
166
|
+
'''Setup application'''
|
|
167
|
+
print(f"Database: {config.get('database')}")
|
|
168
|
+
|
|
169
|
+
@command()
|
|
170
|
+
@config_file("config.ini", section="api")
|
|
171
|
+
def api(config: dict):
|
|
172
|
+
'''Make API call'''
|
|
173
|
+
print(f"URL: {config.get('url')}")
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
def decorator(f: Callable) -> Callable:
|
|
177
|
+
f._config = { # type: ignore[attr-defined]
|
|
178
|
+
"path": path,
|
|
179
|
+
"section": section,
|
|
180
|
+
"required": required,
|
|
181
|
+
"auto_create": auto_create,
|
|
182
|
+
"format": format,
|
|
183
|
+
}
|
|
184
|
+
return f
|
|
185
|
+
|
|
186
|
+
return decorator
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def version_option(
|
|
190
|
+
version: Optional[str] = None,
|
|
191
|
+
prog_name: Optional[str] = None,
|
|
192
|
+
message: Optional[str] = None,
|
|
193
|
+
package_name: Optional[str] = None,
|
|
194
|
+
) -> Callable:
|
|
195
|
+
"""
|
|
196
|
+
Decorator to add version option to command.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
version: Version string
|
|
200
|
+
prog_name: Program name
|
|
201
|
+
message: Custom version message
|
|
202
|
+
package_name: Package name to get version from
|
|
203
|
+
|
|
204
|
+
Example:
|
|
205
|
+
@command()
|
|
206
|
+
@version_option(version="1.0.0")
|
|
207
|
+
def main():
|
|
208
|
+
'''Main command'''
|
|
209
|
+
pass
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
def decorator(f: Callable) -> Callable:
|
|
213
|
+
f._version = { # type: ignore[attr-defined]
|
|
214
|
+
"version": version,
|
|
215
|
+
"prog_name": prog_name,
|
|
216
|
+
"message": message,
|
|
217
|
+
"package_name": package_name,
|
|
218
|
+
}
|
|
219
|
+
return f
|
|
220
|
+
|
|
221
|
+
return decorator
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def help_option(param_decls: Optional[List[str]] = None, help: Optional[str] = None) -> Callable:
|
|
225
|
+
"""
|
|
226
|
+
Decorator to customize help option.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
param_decls: Help option flags
|
|
230
|
+
help: Help text
|
|
231
|
+
|
|
232
|
+
Example:
|
|
233
|
+
@command()
|
|
234
|
+
@help_option(["--help", "-h"], "Show this message")
|
|
235
|
+
def main():
|
|
236
|
+
'''Main command'''
|
|
237
|
+
pass
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
def decorator(f: Callable) -> Callable:
|
|
241
|
+
f._help_option = { # type: ignore[attr-defined]
|
|
242
|
+
"param_decls": param_decls or ["--help", "-h"],
|
|
243
|
+
"help": help or "Show this message and exit.",
|
|
244
|
+
}
|
|
245
|
+
return f
|
|
246
|
+
|
|
247
|
+
return decorator
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"""Output formatting decorators for SwiftCLI."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from functools import wraps
|
|
5
|
+
from typing import TYPE_CHECKING, Callable, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from rich.progress import (
|
|
14
|
+
BarColumn,
|
|
15
|
+
Progress,
|
|
16
|
+
SpinnerColumn,
|
|
17
|
+
TaskProgressColumn,
|
|
18
|
+
TextColumn,
|
|
19
|
+
TimeRemainingColumn,
|
|
20
|
+
)
|
|
21
|
+
else:
|
|
22
|
+
# Handle different versions of rich
|
|
23
|
+
try:
|
|
24
|
+
from rich.progress import (
|
|
25
|
+
BarColumn,
|
|
26
|
+
Progress,
|
|
27
|
+
SpinnerColumn,
|
|
28
|
+
TaskProgressColumn,
|
|
29
|
+
TextColumn,
|
|
30
|
+
TimeRemainingColumn,
|
|
31
|
+
)
|
|
32
|
+
except ImportError:
|
|
33
|
+
# If standard imports fail, try older rich versions or create minimal fallbacks
|
|
34
|
+
try:
|
|
35
|
+
from rich.progress import (
|
|
36
|
+
BarColumn,
|
|
37
|
+
Progress,
|
|
38
|
+
SpinnerColumn,
|
|
39
|
+
TextColumn,
|
|
40
|
+
TimeRemainingColumn,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Create a simple TaskProgressColumn replacement for older versions
|
|
44
|
+
class TaskProgressColumn:
|
|
45
|
+
def __init__(self):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
def __call__(self, task):
|
|
49
|
+
return f"{task.percentage:.1f}%"
|
|
50
|
+
except ImportError:
|
|
51
|
+
# If rich is too old or not installed, create minimal fallbacks
|
|
52
|
+
class Progress:
|
|
53
|
+
def __init__(self, *args, **kwargs):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
def __enter__(self):
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
def __exit__(self, *args):
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
def add_task(self, description, total=None):
|
|
63
|
+
return 0
|
|
64
|
+
|
|
65
|
+
def update(self, task_id, **kwargs):
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
class SpinnerColumn:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
class TextColumn:
|
|
72
|
+
def __init__(self, text):
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
class BarColumn:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
class TaskProgressColumn:
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
class TimeRemainingColumn:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
console = Console()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def table_output(
|
|
89
|
+
headers: List[str],
|
|
90
|
+
title: Optional[str] = None,
|
|
91
|
+
style: str = "default",
|
|
92
|
+
show_lines: bool = False,
|
|
93
|
+
expand: bool = False,
|
|
94
|
+
) -> Callable:
|
|
95
|
+
"""
|
|
96
|
+
Decorator to format command output as a table.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
headers: Column headers
|
|
100
|
+
title: Table title
|
|
101
|
+
style: Table style
|
|
102
|
+
show_lines: Show row/column lines
|
|
103
|
+
expand: Expand table to terminal width
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
@command()
|
|
107
|
+
@table_output(["ID", "Name", "Status"])
|
|
108
|
+
def list_users():
|
|
109
|
+
'''List all users'''
|
|
110
|
+
return [
|
|
111
|
+
[1, "John", "Active"],
|
|
112
|
+
[2, "Jane", "Inactive"]
|
|
113
|
+
]
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def decorator(f: Callable) -> Callable:
|
|
117
|
+
@wraps(f)
|
|
118
|
+
def wrapper(*args, **kwargs):
|
|
119
|
+
result = f(*args, **kwargs)
|
|
120
|
+
if result:
|
|
121
|
+
table = Table(
|
|
122
|
+
title=title,
|
|
123
|
+
show_header=True,
|
|
124
|
+
header_style="bold blue",
|
|
125
|
+
show_lines=show_lines,
|
|
126
|
+
expand=expand,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Add columns
|
|
130
|
+
for header in headers:
|
|
131
|
+
table.add_column(header)
|
|
132
|
+
|
|
133
|
+
# Add rows
|
|
134
|
+
for row in result:
|
|
135
|
+
table.add_row(*[str(cell) for cell in row])
|
|
136
|
+
|
|
137
|
+
console.print(table)
|
|
138
|
+
return result
|
|
139
|
+
|
|
140
|
+
return wrapper
|
|
141
|
+
|
|
142
|
+
return decorator
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def json_output(indent: int = 2, sort_keys: bool = False, ensure_ascii: bool = False) -> Callable:
|
|
146
|
+
"""
|
|
147
|
+
Decorator to format command output as JSON.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
indent: Indentation level for pretty printing
|
|
151
|
+
sort_keys: Whether to sort dictionary keys
|
|
152
|
+
ensure_ascii: Whether to escape non-ASCII characters
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
@command()
|
|
156
|
+
@json_output(indent=2)
|
|
157
|
+
def get_data():
|
|
158
|
+
'''Get data as JSON'''
|
|
159
|
+
return {"status": "success", "data": [1, 2, 3]}
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
def decorator(f: Callable) -> Callable:
|
|
163
|
+
@wraps(f)
|
|
164
|
+
def wrapper(*args, **kwargs):
|
|
165
|
+
result = f(*args, **kwargs)
|
|
166
|
+
if result:
|
|
167
|
+
json_str = json.dumps(
|
|
168
|
+
result, indent=indent, sort_keys=sort_keys, ensure_ascii=ensure_ascii
|
|
169
|
+
)
|
|
170
|
+
console.print(json_str)
|
|
171
|
+
return result
|
|
172
|
+
|
|
173
|
+
return wrapper
|
|
174
|
+
|
|
175
|
+
return decorator
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def yaml_output(default_flow_style: bool = False, sort_keys: bool = False) -> Callable:
|
|
179
|
+
"""
|
|
180
|
+
Decorator to format command output as YAML.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
default_flow_style: Whether to use flow style for collections
|
|
184
|
+
sort_keys: Whether to sort dictionary keys
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
@command()
|
|
188
|
+
@yaml_output()
|
|
189
|
+
def get_config():
|
|
190
|
+
'''Get configuration as YAML'''
|
|
191
|
+
return {"database": {"host": "localhost", "port": 5432}}
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def decorator(f: Callable) -> Callable:
|
|
195
|
+
@wraps(f)
|
|
196
|
+
def wrapper(*args, **kwargs):
|
|
197
|
+
result = f(*args, **kwargs)
|
|
198
|
+
if result:
|
|
199
|
+
yaml_str = yaml.safe_dump(
|
|
200
|
+
result, default_flow_style=default_flow_style, sort_keys=sort_keys
|
|
201
|
+
)
|
|
202
|
+
console.print(yaml_str)
|
|
203
|
+
return result
|
|
204
|
+
|
|
205
|
+
return wrapper
|
|
206
|
+
|
|
207
|
+
return decorator
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def progress(
|
|
211
|
+
description: Optional[str] = None,
|
|
212
|
+
total: Optional[int] = None,
|
|
213
|
+
transient: bool = False,
|
|
214
|
+
show_bar: bool = True,
|
|
215
|
+
show_percentage: bool = True,
|
|
216
|
+
show_time: bool = True,
|
|
217
|
+
) -> Callable:
|
|
218
|
+
"""
|
|
219
|
+
Decorator to show progress for long-running commands.
|
|
220
|
+
|
|
221
|
+
The decorated function should be a generator that yields
|
|
222
|
+
progress updates.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
description: Task description
|
|
226
|
+
total: Total number of steps
|
|
227
|
+
transient: Remove progress when done
|
|
228
|
+
show_bar: Show progress bar
|
|
229
|
+
show_percentage: Show percentage complete
|
|
230
|
+
show_time: Show time remaining
|
|
231
|
+
|
|
232
|
+
Example:
|
|
233
|
+
@command()
|
|
234
|
+
@progress("Processing files")
|
|
235
|
+
def process(files: List[str]):
|
|
236
|
+
'''Process multiple files'''
|
|
237
|
+
for file in files:
|
|
238
|
+
# Process file
|
|
239
|
+
yield f"Processing {file}..."
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
def decorator(f: Callable) -> Callable:
|
|
243
|
+
@wraps(f)
|
|
244
|
+
def wrapper(*args, **kwargs):
|
|
245
|
+
columns = []
|
|
246
|
+
columns.append(SpinnerColumn())
|
|
247
|
+
columns.append(TextColumn("[progress.description]{task.description}"))
|
|
248
|
+
|
|
249
|
+
if show_bar:
|
|
250
|
+
columns.append(BarColumn())
|
|
251
|
+
if show_percentage:
|
|
252
|
+
try:
|
|
253
|
+
columns.append(TaskProgressColumn())
|
|
254
|
+
except Exception:
|
|
255
|
+
# Fallback for older rich versions
|
|
256
|
+
columns.append(TextColumn("[progress.percentage]{task.percentage:>3.0f}%"))
|
|
257
|
+
if show_time:
|
|
258
|
+
columns.append(TimeRemainingColumn())
|
|
259
|
+
|
|
260
|
+
with Progress(*columns, transient=transient) as progress:
|
|
261
|
+
task = progress.add_task(description or getattr(f, '__name__', 'unknown'), total=total)
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
for update in f(*args, **kwargs):
|
|
265
|
+
if isinstance(update, (int, float)):
|
|
266
|
+
# Update progress by number
|
|
267
|
+
progress.update(task, advance=update)
|
|
268
|
+
elif isinstance(update, str):
|
|
269
|
+
# Update description
|
|
270
|
+
progress.update(task, description=update)
|
|
271
|
+
elif isinstance(update, dict):
|
|
272
|
+
# Update multiple attributes
|
|
273
|
+
progress.update(task, **update)
|
|
274
|
+
else:
|
|
275
|
+
# Just advance by 1
|
|
276
|
+
progress.update(task, advance=1)
|
|
277
|
+
except Exception as e:
|
|
278
|
+
progress.update(task, description=f"Error: {str(e)}")
|
|
279
|
+
raise
|
|
280
|
+
finally:
|
|
281
|
+
progress.update(task, completed=total or 100)
|
|
282
|
+
|
|
283
|
+
return wrapper
|
|
284
|
+
|
|
285
|
+
return decorator
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def panel_output(
|
|
289
|
+
title: Optional[str] = None,
|
|
290
|
+
style: str = "default",
|
|
291
|
+
expand: bool = True,
|
|
292
|
+
padding: Union[int, tuple] = 1,
|
|
293
|
+
) -> Callable:
|
|
294
|
+
"""
|
|
295
|
+
Decorator to display command output in a panel.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
title: Panel title
|
|
299
|
+
style: Panel style
|
|
300
|
+
expand: Expand panel to terminal width
|
|
301
|
+
padding: Panel padding
|
|
302
|
+
|
|
303
|
+
Example:
|
|
304
|
+
@command()
|
|
305
|
+
@panel_output(title="System Status")
|
|
306
|
+
def status():
|
|
307
|
+
'''Show system status'''
|
|
308
|
+
return "All systems operational"
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
def decorator(f: Callable) -> Callable:
|
|
312
|
+
@wraps(f)
|
|
313
|
+
def wrapper(*args, **kwargs):
|
|
314
|
+
result = f(*args, **kwargs)
|
|
315
|
+
if result:
|
|
316
|
+
panel = Panel(str(result), title=title, style=style, expand=expand, padding=padding)
|
|
317
|
+
console.print(panel)
|
|
318
|
+
return result
|
|
319
|
+
|
|
320
|
+
return wrapper
|
|
321
|
+
|
|
322
|
+
return decorator
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def format_output(template: str, style: Optional[str] = None) -> Callable:
|
|
326
|
+
"""
|
|
327
|
+
Decorator to format command output using a template.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
template: Format string template
|
|
331
|
+
style: Rich style string
|
|
332
|
+
|
|
333
|
+
Example:
|
|
334
|
+
@command()
|
|
335
|
+
@format_output("Created user {name} with ID {id}")
|
|
336
|
+
def create_user(name: str):
|
|
337
|
+
'''Create a new user'''
|
|
338
|
+
return {"name": name, "id": 123}
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
def decorator(f: Callable) -> Callable:
|
|
342
|
+
@wraps(f)
|
|
343
|
+
def wrapper(*args, **kwargs):
|
|
344
|
+
result = f(*args, **kwargs)
|
|
345
|
+
if result:
|
|
346
|
+
if isinstance(result, dict):
|
|
347
|
+
output = template.format(**result)
|
|
348
|
+
else:
|
|
349
|
+
output = template.format(result)
|
|
350
|
+
|
|
351
|
+
if style:
|
|
352
|
+
console.print(output, style=style)
|
|
353
|
+
else:
|
|
354
|
+
console.print(output)
|
|
355
|
+
return result
|
|
356
|
+
|
|
357
|
+
return wrapper
|
|
358
|
+
|
|
359
|
+
return decorator
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def pager_output(use_pager: bool = True, style: Optional[str] = None) -> Callable:
|
|
363
|
+
"""
|
|
364
|
+
Decorator to display command output in a pager.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
use_pager: Whether to use pager
|
|
368
|
+
style: Rich style string
|
|
369
|
+
|
|
370
|
+
Example:
|
|
371
|
+
@command()
|
|
372
|
+
@pager_output()
|
|
373
|
+
def show_logs():
|
|
374
|
+
'''Show application logs'''
|
|
375
|
+
return "Very long log output..."
|
|
376
|
+
"""
|
|
377
|
+
|
|
378
|
+
def decorator(f: Callable) -> Callable:
|
|
379
|
+
@wraps(f)
|
|
380
|
+
def wrapper(*args, **kwargs):
|
|
381
|
+
result = f(*args, **kwargs)
|
|
382
|
+
if result:
|
|
383
|
+
with console.pager(styles=use_pager):
|
|
384
|
+
if style:
|
|
385
|
+
console.print(result, style=style)
|
|
386
|
+
else:
|
|
387
|
+
console.print(result)
|
|
388
|
+
return result
|
|
389
|
+
|
|
390
|
+
return wrapper
|
|
391
|
+
|
|
392
|
+
return decorator
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Exception classes for SwiftCLI."""
|
|
2
|
+
|
|
3
|
+
class SwiftCLIException(Exception):
|
|
4
|
+
"""Base exception class for SwiftCLI."""
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
class UsageError(SwiftCLIException):
|
|
8
|
+
"""Raised when CLI is used incorrectly."""
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
class BadParameter(UsageError):
|
|
12
|
+
"""Raised when a parameter is invalid."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
class ConfigError(SwiftCLIException):
|
|
16
|
+
"""Raised when there is a configuration error."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
class PluginError(SwiftCLIException):
|
|
20
|
+
"""Raised when there is a plugin error."""
|
|
21
|
+
pass
|