webscout 8.2.9__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 -251
- webscout/AIbase.py +247 -319
- webscout/AIutel.py +68 -703
- webscout/Bard.py +1072 -1026
- webscout/Extra/GitToolkit/__init__.py +10 -10
- 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 -375
- 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 -44
- 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 -118
- 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 +403 -232
- webscout/Extra/__init__.py +2 -3
- webscout/Extra/gguf.py +1298 -684
- webscout/Extra/tempmail/README.md +487 -487
- 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 +292 -333
- webscout/Provider/AISEARCH/README.md +106 -279
- webscout/Provider/AISEARCH/__init__.py +16 -9
- webscout/Provider/AISEARCH/brave_search.py +298 -0
- webscout/Provider/AISEARCH/iask_search.py +357 -410
- webscout/Provider/AISEARCH/monica_search.py +200 -220
- webscout/Provider/AISEARCH/webpilotai_search.py +242 -255
- 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 -342
- webscout/Provider/ClaudeOnline.py +365 -0
- webscout/Provider/Cohere.py +232 -208
- webscout/Provider/DeepAI.py +367 -0
- webscout/Provider/Deepinfra.py +467 -340
- webscout/Provider/EssentialAI.py +217 -0
- webscout/Provider/ExaAI.py +274 -261
- webscout/Provider/Gemini.py +175 -169
- webscout/Provider/GithubChat.py +385 -369
- webscout/Provider/Gradient.py +286 -0
- webscout/Provider/Groq.py +556 -801
- webscout/Provider/HadadXYZ.py +323 -0
- webscout/Provider/HeckAI.py +392 -375
- webscout/Provider/HuggingFace.py +387 -0
- webscout/Provider/IBM.py +340 -0
- webscout/Provider/Jadve.py +317 -291
- webscout/Provider/K2Think.py +306 -0
- webscout/Provider/Koboldai.py +221 -384
- webscout/Provider/Netwrck.py +273 -270
- 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 -952
- webscout/Provider/OPENAI/TogetherAI.py +405 -0
- webscout/Provider/OPENAI/TwoAI.py +255 -357
- webscout/Provider/OPENAI/__init__.py +148 -40
- webscout/Provider/OPENAI/ai4chat.py +348 -293
- webscout/Provider/OPENAI/akashgpt.py +436 -0
- webscout/Provider/OPENAI/algion.py +303 -0
- webscout/Provider/OPENAI/{exachat.py → ayle.py} +365 -444
- webscout/Provider/OPENAI/base.py +253 -249
- webscout/Provider/OPENAI/cerebras.py +296 -0
- webscout/Provider/OPENAI/chatgpt.py +870 -556
- webscout/Provider/OPENAI/chatsandbox.py +233 -173
- webscout/Provider/OPENAI/deepinfra.py +403 -322
- webscout/Provider/OPENAI/e2b.py +2370 -1414
- webscout/Provider/OPENAI/elmo.py +278 -0
- webscout/Provider/OPENAI/exaai.py +452 -417
- webscout/Provider/OPENAI/freeassist.py +446 -0
- webscout/Provider/OPENAI/gradient.py +448 -0
- webscout/Provider/OPENAI/groq.py +380 -364
- webscout/Provider/OPENAI/hadadxyz.py +292 -0
- webscout/Provider/OPENAI/heckai.py +333 -308
- 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 -335
- webscout/Provider/OPENAI/meta.py +541 -0
- webscout/Provider/OPENAI/netwrck.py +374 -357
- webscout/Provider/OPENAI/nvidia.py +317 -0
- webscout/Provider/OPENAI/oivscode.py +348 -287
- webscout/Provider/OPENAI/openrouter.py +328 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -172
- webscout/Provider/OPENAI/sambanova.py +397 -0
- webscout/Provider/OPENAI/sonus.py +305 -304
- webscout/Provider/OPENAI/textpollinations.py +370 -339
- webscout/Provider/OPENAI/toolbaz.py +375 -413
- webscout/Provider/OPENAI/typefully.py +419 -355
- webscout/Provider/OPENAI/typliai.py +279 -0
- webscout/Provider/OPENAI/utils.py +314 -318
- webscout/Provider/OPENAI/wisecat.py +359 -387
- webscout/Provider/OPENAI/writecream.py +185 -163
- webscout/Provider/OPENAI/x0gpt.py +462 -365
- webscout/Provider/OPENAI/zenmux.py +380 -0
- webscout/Provider/OpenRouter.py +386 -0
- webscout/Provider/Openai.py +337 -496
- webscout/Provider/PI.py +443 -429
- 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 -82
- webscout/Provider/TTI/__init__.py +37 -7
- webscout/Provider/TTI/base.py +147 -64
- webscout/Provider/TTI/claudeonline.py +393 -0
- webscout/Provider/TTI/magicstudio.py +292 -201
- webscout/Provider/TTI/miragic.py +180 -0
- webscout/Provider/TTI/pollinations.py +331 -221
- webscout/Provider/TTI/together.py +334 -0
- webscout/Provider/TTI/utils.py +14 -11
- webscout/Provider/TTS/README.md +186 -192
- webscout/Provider/TTS/__init__.py +43 -10
- webscout/Provider/TTS/base.py +523 -159
- 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 -129
- 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 -580
- webscout/Provider/TTS/streamElements.py +275 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TextPollinationsAI.py +331 -308
- webscout/Provider/TogetherAI.py +450 -0
- webscout/Provider/TwoAI.py +309 -475
- webscout/Provider/TypliAI.py +311 -305
- webscout/Provider/UNFINISHED/ChatHub.py +219 -209
- webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +331 -326
- webscout/Provider/{GizAI.py → UNFINISHED/GizAI.py} +300 -295
- webscout/Provider/{Marcus.py → UNFINISHED/Marcus.py} +218 -198
- webscout/Provider/UNFINISHED/Qodo.py +481 -0
- webscout/Provider/{MCPCore.py → UNFINISHED/XenAI.py} +330 -315
- webscout/Provider/UNFINISHED/Youchat.py +347 -330
- 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 -263
- webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +231 -224
- webscout/Provider/WiseCat.py +256 -233
- webscout/Provider/WrDoChat.py +390 -370
- webscout/Provider/__init__.py +115 -174
- webscout/Provider/ai4chat.py +181 -174
- webscout/Provider/akashgpt.py +330 -335
- webscout/Provider/cerebras.py +397 -290
- webscout/Provider/cleeai.py +236 -213
- webscout/Provider/elmo.py +291 -283
- webscout/Provider/geminiapi.py +343 -208
- webscout/Provider/julius.py +245 -223
- webscout/Provider/learnfastai.py +333 -325
- webscout/Provider/llama3mitril.py +230 -215
- webscout/Provider/llmchat.py +308 -258
- webscout/Provider/llmchatco.py +321 -306
- webscout/Provider/meta.py +996 -801
- webscout/Provider/oivscode.py +332 -309
- webscout/Provider/searchchat.py +316 -292
- webscout/Provider/sonus.py +264 -258
- webscout/Provider/toolbaz.py +359 -353
- webscout/Provider/turboseek.py +332 -266
- webscout/Provider/typefully.py +262 -202
- webscout/Provider/x0gpt.py +332 -299
- webscout/__init__.py +31 -39
- webscout/__main__.py +5 -5
- webscout/cli.py +585 -524
- webscout/client.py +1497 -70
- webscout/conversation.py +140 -436
- webscout/exceptions.py +383 -362
- 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 +74 -420
- webscout/prompt_manager.py +376 -288
- webscout/sanitize.py +1514 -0
- webscout/scout/README.md +452 -404
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +7 -7
- webscout/scout/core/crawler.py +330 -210
- webscout/scout/core/scout.py +800 -607
- 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 -478
- 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 -95
- webscout/swiftcli/core/__init__.py +7 -7
- webscout/swiftcli/core/cli.py +574 -297
- webscout/swiftcli/core/context.py +98 -104
- webscout/swiftcli/core/group.py +268 -241
- webscout/swiftcli/decorators/__init__.py +28 -28
- webscout/swiftcli/decorators/command.py +243 -221
- webscout/swiftcli/decorators/options.py +247 -220
- webscout/swiftcli/decorators/output.py +392 -252
- webscout/swiftcli/exceptions.py +21 -21
- webscout/swiftcli/plugins/__init__.py +9 -9
- webscout/swiftcli/plugins/base.py +134 -135
- webscout/swiftcli/plugins/manager.py +269 -269
- webscout/swiftcli/utils/__init__.py +58 -59
- webscout/swiftcli/utils/formatting.py +251 -252
- webscout/swiftcli/utils/parsing.py +368 -267
- 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 -135
- webscout/zeroart/base.py +70 -66
- webscout/zeroart/effects.py +155 -101
- webscout/zeroart/fonts.py +1799 -1239
- webscout-2026.1.19.dist-info/METADATA +638 -0
- webscout-2026.1.19.dist-info/RECORD +312 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/entry_points.txt +1 -1
- webscout/DWEBS.py +0 -520
- webscout/Extra/Act.md +0 -309
- webscout/Extra/GitToolkit/gitapi/README.md +0 -110
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -1105
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/Extra/gguf.md +0 -430
- webscout/Extra/weather.md +0 -281
- webscout/Litlogger/README.md +0 -10
- webscout/Litlogger/__init__.py +0 -15
- webscout/Litlogger/formats.py +0 -4
- webscout/Litlogger/handlers.py +0 -103
- webscout/Litlogger/levels.py +0 -13
- webscout/Litlogger/logger.py +0 -92
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -254
- webscout/Provider/AISEARCH/felo_search.py +0 -202
- webscout/Provider/AISEARCH/genspark_search.py +0 -324
- webscout/Provider/AISEARCH/hika_search.py +0 -186
- webscout/Provider/AISEARCH/scira_search.py +0 -298
- webscout/Provider/Aitopia.py +0 -316
- webscout/Provider/AllenAI.py +0 -440
- webscout/Provider/Blackboxai.py +0 -791
- webscout/Provider/ChatGPTClone.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/Cloudflare.py +0 -324
- webscout/Provider/ExaChat.py +0 -358
- webscout/Provider/Flowith.py +0 -217
- webscout/Provider/FreeGemini.py +0 -250
- webscout/Provider/Glider.py +0 -225
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/LambdaChat.py +0 -411
- webscout/Provider/Llama3.py +0 -259
- webscout/Provider/Nemotron.py +0 -218
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -766
- webscout/Provider/OPENAI/Cloudflare.py +0 -378
- webscout/Provider/OPENAI/FreeGemini.py +0 -283
- webscout/Provider/OPENAI/NEMOTRON.py +0 -232
- webscout/Provider/OPENAI/Qwen3.py +0 -283
- webscout/Provider/OPENAI/api.py +0 -969
- webscout/Provider/OPENAI/c4ai.py +0 -373
- webscout/Provider/OPENAI/chatgptclone.py +0 -494
- webscout/Provider/OPENAI/copilot.py +0 -242
- webscout/Provider/OPENAI/flowith.py +0 -162
- webscout/Provider/OPENAI/freeaichat.py +0 -359
- webscout/Provider/OPENAI/mcpcore.py +0 -389
- webscout/Provider/OPENAI/multichat.py +0 -376
- webscout/Provider/OPENAI/opkfc.py +0 -496
- webscout/Provider/OPENAI/scirachat.py +0 -477
- webscout/Provider/OPENAI/standardinput.py +0 -433
- webscout/Provider/OPENAI/typegpt.py +0 -364
- webscout/Provider/OPENAI/uncovrAI.py +0 -463
- webscout/Provider/OPENAI/venice.py +0 -431
- webscout/Provider/OPENAI/yep.py +0 -382
- webscout/Provider/OpenGPT.py +0 -209
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -290
- webscout/Provider/TTI/aiarta.py +0 -365
- webscout/Provider/TTI/artbit.py +0 -0
- webscout/Provider/TTI/fastflux.py +0 -200
- webscout/Provider/TTI/piclumen.py +0 -203
- webscout/Provider/TTI/pixelmuse.py +0 -225
- webscout/Provider/TTS/gesserit.py +0 -128
- webscout/Provider/TTS/sthir.py +0 -94
- webscout/Provider/TeachAnything.py +0 -229
- webscout/Provider/UNFINISHED/puterjs.py +0 -635
- webscout/Provider/UNFINISHED/test_lmarena.py +0 -119
- webscout/Provider/Venice.py +0 -258
- webscout/Provider/VercelAI.py +0 -253
- webscout/Provider/Writecream.py +0 -246
- webscout/Provider/WritingMate.py +0 -269
- webscout/Provider/asksteve.py +0 -220
- webscout/Provider/chatglm.py +0 -215
- webscout/Provider/copilot.py +0 -425
- webscout/Provider/freeaichat.py +0 -285
- webscout/Provider/granite.py +0 -235
- webscout/Provider/hermes.py +0 -266
- webscout/Provider/koala.py +0 -170
- webscout/Provider/lmarena.py +0 -198
- webscout/Provider/multichat.py +0 -364
- webscout/Provider/scira_chat.py +0 -299
- webscout/Provider/scnet.py +0 -243
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/typegpt.py +0 -289
- webscout/Provider/uncovr.py +0 -368
- webscout/Provider/yep.py +0 -389
- webscout/litagent/Readme.md +0 -276
- webscout/litprinter/__init__.py +0 -59
- webscout/swiftcli/Readme.md +0 -323
- webscout/tempid.py +0 -128
- webscout/webscout_search.py +0 -1184
- webscout/webscout_search_async.py +0 -654
- webscout/yep_search.py +0 -347
- webscout/zeroart/README.md +0 -89
- webscout-8.2.9.dist-info/METADATA +0 -1033
- webscout-8.2.9.dist-info/RECORD +0 -289
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/top_level.txt +0 -0
webscout/swiftcli/core/group.py
CHANGED
|
@@ -1,241 +1,268 @@
|
|
|
1
|
-
"""Command group handling for SwiftCLI."""
|
|
2
|
-
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
-
|
|
5
|
-
from rich.console import Console
|
|
6
|
-
|
|
7
|
-
from ..
|
|
8
|
-
from
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Group:
|
|
17
|
-
"""
|
|
18
|
-
Command group that can contain subcommands.
|
|
19
|
-
|
|
20
|
-
Groups allow organizing related commands together and support command
|
|
21
|
-
chaining for building command pipelines.
|
|
22
|
-
|
|
23
|
-
Attributes:
|
|
24
|
-
name: Group name
|
|
25
|
-
help: Group description
|
|
26
|
-
commands: Registered commands
|
|
27
|
-
parent: Parent CLI instance
|
|
28
|
-
chain: Enable command chaining
|
|
29
|
-
invoke_without_command: Allow invoking group without subcommand
|
|
30
|
-
|
|
31
|
-
Example:
|
|
32
|
-
@app.group()
|
|
33
|
-
def db():
|
|
34
|
-
'''Database commands'''
|
|
35
|
-
pass
|
|
36
|
-
|
|
37
|
-
@db.command()
|
|
38
|
-
def migrate():
|
|
39
|
-
'''Run database migrations'''
|
|
40
|
-
print("Running migrations...")
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
def __init__(
|
|
44
|
-
self,
|
|
45
|
-
name: str,
|
|
46
|
-
help: Optional[str] = None,
|
|
47
|
-
parent: Optional[
|
|
48
|
-
chain: bool = False,
|
|
49
|
-
invoke_without_command: bool = False
|
|
50
|
-
):
|
|
51
|
-
"""
|
|
52
|
-
Initialize command group.
|
|
53
|
-
|
|
54
|
-
Args:
|
|
55
|
-
name: Group name
|
|
56
|
-
help: Group description
|
|
57
|
-
parent: Parent CLI instance
|
|
58
|
-
chain: Enable command chaining
|
|
59
|
-
invoke_without_command: Allow invoking group without subcommand
|
|
60
|
-
"""
|
|
61
|
-
self.name = name
|
|
62
|
-
self.help = help
|
|
63
|
-
self.parent = parent
|
|
64
|
-
self.chain = chain
|
|
65
|
-
self.invoke_without_command = invoke_without_command
|
|
66
|
-
self.commands: Dict[str,
|
|
67
|
-
|
|
68
|
-
def command(
|
|
69
|
-
self,
|
|
70
|
-
name: Optional[str] = None,
|
|
71
|
-
help: Optional[str] = None,
|
|
72
|
-
aliases: Optional[List[str]] = None,
|
|
73
|
-
hidden: bool = False
|
|
74
|
-
):
|
|
75
|
-
"""
|
|
76
|
-
Decorator to register a command in this group.
|
|
77
|
-
|
|
78
|
-
Args:
|
|
79
|
-
name: Command name (defaults to function name)
|
|
80
|
-
help: Command help text
|
|
81
|
-
aliases: Alternative command names
|
|
82
|
-
hidden: Hide from help output
|
|
83
|
-
|
|
84
|
-
Example:
|
|
85
|
-
@group.command()
|
|
86
|
-
def status():
|
|
87
|
-
'''Show status'''
|
|
88
|
-
print("Status: OK")
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
command
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
self.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
1
|
+
"""Command group handling for SwiftCLI."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
|
|
7
|
+
from ..utils.formatting import format_error
|
|
8
|
+
from .context import Context
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .cli import CLI
|
|
12
|
+
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Group:
|
|
17
|
+
"""
|
|
18
|
+
Command group that can contain subcommands.
|
|
19
|
+
|
|
20
|
+
Groups allow organizing related commands together and support command
|
|
21
|
+
chaining for building command pipelines.
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
name: Group name
|
|
25
|
+
help: Group description
|
|
26
|
+
commands: Registered commands
|
|
27
|
+
parent: Parent CLI instance
|
|
28
|
+
chain: Enable command chaining
|
|
29
|
+
invoke_without_command: Allow invoking group without subcommand
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
@app.group()
|
|
33
|
+
def db():
|
|
34
|
+
'''Database commands'''
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@db.command()
|
|
38
|
+
def migrate():
|
|
39
|
+
'''Run database migrations'''
|
|
40
|
+
print("Running migrations...")
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
name: str,
|
|
46
|
+
help: Optional[str] = None,
|
|
47
|
+
parent: Optional["CLI"] = None,
|
|
48
|
+
chain: bool = False,
|
|
49
|
+
invoke_without_command: bool = False,
|
|
50
|
+
):
|
|
51
|
+
"""
|
|
52
|
+
Initialize command group.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
name: Group name
|
|
56
|
+
help: Group description
|
|
57
|
+
parent: Parent CLI instance
|
|
58
|
+
chain: Enable command chaining
|
|
59
|
+
invoke_without_command: Allow invoking group without subcommand
|
|
60
|
+
"""
|
|
61
|
+
self.name = name
|
|
62
|
+
self.help = help
|
|
63
|
+
self.parent = parent
|
|
64
|
+
self.chain = chain
|
|
65
|
+
self.invoke_without_command = invoke_without_command
|
|
66
|
+
self.commands: Dict[str, Any] = {}
|
|
67
|
+
|
|
68
|
+
def command(
|
|
69
|
+
self,
|
|
70
|
+
name: Optional[str] = None,
|
|
71
|
+
help: Optional[str] = None,
|
|
72
|
+
aliases: Optional[List[str]] = None,
|
|
73
|
+
hidden: bool = False,
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
Decorator to register a command in this group.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
name: Command name (defaults to function name)
|
|
80
|
+
help: Command help text
|
|
81
|
+
aliases: Alternative command names
|
|
82
|
+
hidden: Hide from help output
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
@group.command()
|
|
86
|
+
def status():
|
|
87
|
+
'''Show status'''
|
|
88
|
+
print("Status: OK")
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def decorator(f):
|
|
92
|
+
cmd_name = name or f.__name__
|
|
93
|
+
self.commands[cmd_name] = {
|
|
94
|
+
"name": cmd_name,
|
|
95
|
+
"func": f,
|
|
96
|
+
"help": help or f.__doc__,
|
|
97
|
+
"aliases": aliases or [],
|
|
98
|
+
"hidden": hidden,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Register aliases
|
|
102
|
+
for alias in aliases or []:
|
|
103
|
+
self.commands[alias] = self.commands[cmd_name]
|
|
104
|
+
|
|
105
|
+
return f
|
|
106
|
+
|
|
107
|
+
return decorator
|
|
108
|
+
|
|
109
|
+
def group(self, name: Optional[str] = None, help: Optional[str] = None, **kwargs):
|
|
110
|
+
"""
|
|
111
|
+
Create a subgroup within this group.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
name: Subgroup name
|
|
115
|
+
help: Subgroup help text
|
|
116
|
+
**kwargs: Additional group options
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
@group.group()
|
|
120
|
+
def config():
|
|
121
|
+
'''Configuration commands'''
|
|
122
|
+
pass
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def decorator(f):
|
|
126
|
+
subgroup = Group(
|
|
127
|
+
name=name or f.__name__, help=help or f.__doc__, parent=self.parent, **kwargs
|
|
128
|
+
)
|
|
129
|
+
self.commands[subgroup.name] = subgroup
|
|
130
|
+
return subgroup
|
|
131
|
+
|
|
132
|
+
return decorator
|
|
133
|
+
|
|
134
|
+
def run(self, args: List[str]) -> int:
|
|
135
|
+
"""
|
|
136
|
+
Run a command in this group.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
args: Command arguments
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Exit code (0 for success, non-zero for error)
|
|
143
|
+
"""
|
|
144
|
+
try:
|
|
145
|
+
# Show help if no arguments or help requested
|
|
146
|
+
if not args or args[0] in ["-h", "--help"]:
|
|
147
|
+
self._print_help()
|
|
148
|
+
return 0
|
|
149
|
+
|
|
150
|
+
command_name = args[0]
|
|
151
|
+
command_args = args[1:]
|
|
152
|
+
|
|
153
|
+
# Check if command exists
|
|
154
|
+
if command_name not in self.commands:
|
|
155
|
+
format_error(f"Unknown command: {self.name} {command_name}")
|
|
156
|
+
self._print_help()
|
|
157
|
+
return 1
|
|
158
|
+
|
|
159
|
+
command = self.commands[command_name]
|
|
160
|
+
|
|
161
|
+
# Handle nested groups
|
|
162
|
+
if isinstance(command, Group):
|
|
163
|
+
return command.run(command_args)
|
|
164
|
+
|
|
165
|
+
# Create command context - parent is a CLI instance, never None at this point
|
|
166
|
+
# Context expects CLI type, and self.parent should be set when group is created by CLI
|
|
167
|
+
cli = self.parent
|
|
168
|
+
ctx = Context(
|
|
169
|
+
cli,
|
|
170
|
+
command=f"{self.name} {command_name}",
|
|
171
|
+
debug=getattr(self.parent, "debug", False) if self.parent else False,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Run command through plugin system
|
|
175
|
+
if self.parent and not self.parent.plugin_manager.before_command(
|
|
176
|
+
f"{self.name} {command_name}", command_args
|
|
177
|
+
):
|
|
178
|
+
return 1
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
import asyncio
|
|
182
|
+
import inspect
|
|
183
|
+
|
|
184
|
+
func = command["func"]
|
|
185
|
+
params = self._parse_args(command, command_args)
|
|
186
|
+
|
|
187
|
+
# Inject context if function was decorated with pass_context
|
|
188
|
+
if getattr(func, "_pass_context", False):
|
|
189
|
+
call_args = (ctx,)
|
|
190
|
+
else:
|
|
191
|
+
call_args = ()
|
|
192
|
+
|
|
193
|
+
# If coroutine function, run it using asyncio
|
|
194
|
+
if inspect.iscoroutinefunction(func):
|
|
195
|
+
result = asyncio.run(func(*call_args, **params))
|
|
196
|
+
else:
|
|
197
|
+
result = func(*call_args, **params)
|
|
198
|
+
|
|
199
|
+
# If function returned a coroutine-like object
|
|
200
|
+
if not inspect.iscoroutine(result) and hasattr(result, "__await__"):
|
|
201
|
+
result = asyncio.run(result)
|
|
202
|
+
|
|
203
|
+
if self.parent:
|
|
204
|
+
self.parent.plugin_manager.after_command(
|
|
205
|
+
f"{self.name} {command_name}", command_args, result
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Handle command chaining
|
|
209
|
+
if self.chain and result is not None:
|
|
210
|
+
return result if isinstance(result, int) else 0
|
|
211
|
+
|
|
212
|
+
return 0
|
|
213
|
+
|
|
214
|
+
except Exception as e:
|
|
215
|
+
if self.parent:
|
|
216
|
+
self.parent.plugin_manager.on_error(f"{self.name} {command_name}", e)
|
|
217
|
+
if getattr(self.parent, "debug", False):
|
|
218
|
+
raise
|
|
219
|
+
format_error(str(e))
|
|
220
|
+
return 1
|
|
221
|
+
|
|
222
|
+
except Exception as e:
|
|
223
|
+
if getattr(self.parent, "debug", False):
|
|
224
|
+
raise
|
|
225
|
+
format_error(str(e))
|
|
226
|
+
return 1
|
|
227
|
+
|
|
228
|
+
def _parse_args(self, command: Dict[str, Any], args: List[str]) -> Dict[str, Any]:
|
|
229
|
+
"""Parse command arguments."""
|
|
230
|
+
# Use parent CLI's argument parser if available
|
|
231
|
+
if self.parent:
|
|
232
|
+
return self.parent._parse_args(command, args)
|
|
233
|
+
|
|
234
|
+
# Fallback to basic argument parsing
|
|
235
|
+
from ..utils.parsing import parse_args
|
|
236
|
+
|
|
237
|
+
return parse_args(args)
|
|
238
|
+
|
|
239
|
+
def _print_help(self) -> None:
|
|
240
|
+
"""Print group help message."""
|
|
241
|
+
console.print(f"\n[bold]{self.name}[/] - {self.help or ''}")
|
|
242
|
+
|
|
243
|
+
console.print("\n[bold]Commands:[/]")
|
|
244
|
+
printed = set()
|
|
245
|
+
for name, cmd in self.commands.items():
|
|
246
|
+
# cmd can be a Group or a dict mapping
|
|
247
|
+
if isinstance(cmd, Group):
|
|
248
|
+
primary = cmd.name
|
|
249
|
+
if primary in printed:
|
|
250
|
+
continue
|
|
251
|
+
printed.add(primary)
|
|
252
|
+
console.print(f" {primary} [group]")
|
|
253
|
+
if cmd.help:
|
|
254
|
+
console.print(f" {cmd.help}")
|
|
255
|
+
elif isinstance(cmd, dict):
|
|
256
|
+
primary = cmd.get("name", name)
|
|
257
|
+
if primary in printed:
|
|
258
|
+
continue
|
|
259
|
+
printed.add(primary)
|
|
260
|
+
if not cmd.get("hidden", False):
|
|
261
|
+
aliases = cmd.get("aliases", [])
|
|
262
|
+
alias_text = f" (aliases: {', '.join(aliases)})" if aliases else ""
|
|
263
|
+
console.print(f" {primary:20} {cmd['help'] or ''}{alias_text}")
|
|
264
|
+
|
|
265
|
+
console.print("\nUse -h or --help with any command for more info")
|
|
266
|
+
|
|
267
|
+
def __repr__(self) -> str:
|
|
268
|
+
return f"<Group name={self.name}>"
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
"""Decorators for SwiftCLI."""
|
|
2
|
-
|
|
3
|
-
from .command import
|
|
4
|
-
from .options import
|
|
5
|
-
from .output import
|
|
6
|
-
|
|
7
|
-
__all__ = [
|
|
8
|
-
# Command decorators
|
|
9
|
-
'command',
|
|
10
|
-
'group',
|
|
11
|
-
'argument',
|
|
12
|
-
'flag',
|
|
13
|
-
'pass_context',
|
|
14
|
-
|
|
15
|
-
# Option decorators
|
|
16
|
-
'option',
|
|
17
|
-
'envvar',
|
|
18
|
-
'config_file',
|
|
19
|
-
'version_option',
|
|
20
|
-
'help_option',
|
|
21
|
-
|
|
22
|
-
# Output decorators
|
|
23
|
-
'table_output',
|
|
24
|
-
'progress',
|
|
25
|
-
'panel_output',
|
|
26
|
-
'format_output',
|
|
27
|
-
'pager_output'
|
|
28
|
-
]
|
|
1
|
+
"""Decorators for SwiftCLI."""
|
|
2
|
+
|
|
3
|
+
from .command import argument, command, flag, group, pass_context
|
|
4
|
+
from .options import config_file, envvar, help_option, option, version_option
|
|
5
|
+
from .output import format_output, pager_output, panel_output, progress, table_output
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
# Command decorators
|
|
9
|
+
'command',
|
|
10
|
+
'group',
|
|
11
|
+
'argument',
|
|
12
|
+
'flag',
|
|
13
|
+
'pass_context',
|
|
14
|
+
|
|
15
|
+
# Option decorators
|
|
16
|
+
'option',
|
|
17
|
+
'envvar',
|
|
18
|
+
'config_file',
|
|
19
|
+
'version_option',
|
|
20
|
+
'help_option',
|
|
21
|
+
|
|
22
|
+
# Output decorators
|
|
23
|
+
'table_output',
|
|
24
|
+
'progress',
|
|
25
|
+
'panel_output',
|
|
26
|
+
'format_output',
|
|
27
|
+
'pager_output'
|
|
28
|
+
]
|