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.
Files changed (483) hide show
  1. webscout/AIauto.py +524 -143
  2. webscout/AIbase.py +247 -123
  3. webscout/AIutel.py +68 -132
  4. webscout/Bard.py +1072 -535
  5. webscout/Extra/GitToolkit/__init__.py +2 -2
  6. webscout/Extra/GitToolkit/gitapi/__init__.py +20 -12
  7. webscout/Extra/GitToolkit/gitapi/gist.py +142 -0
  8. webscout/Extra/GitToolkit/gitapi/organization.py +91 -0
  9. webscout/Extra/GitToolkit/gitapi/repository.py +308 -195
  10. webscout/Extra/GitToolkit/gitapi/search.py +162 -0
  11. webscout/Extra/GitToolkit/gitapi/trending.py +236 -0
  12. webscout/Extra/GitToolkit/gitapi/user.py +128 -96
  13. webscout/Extra/GitToolkit/gitapi/utils.py +82 -62
  14. webscout/Extra/YTToolkit/README.md +443 -0
  15. webscout/Extra/YTToolkit/YTdownloader.py +953 -957
  16. webscout/Extra/YTToolkit/__init__.py +3 -3
  17. webscout/Extra/YTToolkit/transcriber.py +595 -476
  18. webscout/Extra/YTToolkit/ytapi/README.md +230 -0
  19. webscout/Extra/YTToolkit/ytapi/__init__.py +22 -6
  20. webscout/Extra/YTToolkit/ytapi/captions.py +190 -0
  21. webscout/Extra/YTToolkit/ytapi/channel.py +302 -307
  22. webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
  23. webscout/Extra/YTToolkit/ytapi/extras.py +178 -45
  24. webscout/Extra/YTToolkit/ytapi/hashtag.py +120 -0
  25. webscout/Extra/YTToolkit/ytapi/https.py +89 -88
  26. webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
  27. webscout/Extra/YTToolkit/ytapi/playlist.py +59 -59
  28. webscout/Extra/YTToolkit/ytapi/pool.py +8 -8
  29. webscout/Extra/YTToolkit/ytapi/query.py +143 -40
  30. webscout/Extra/YTToolkit/ytapi/shorts.py +122 -0
  31. webscout/Extra/YTToolkit/ytapi/stream.py +68 -63
  32. webscout/Extra/YTToolkit/ytapi/suggestions.py +97 -0
  33. webscout/Extra/YTToolkit/ytapi/utils.py +66 -62
  34. webscout/Extra/YTToolkit/ytapi/video.py +189 -18
  35. webscout/Extra/__init__.py +2 -3
  36. webscout/Extra/gguf.py +1298 -682
  37. webscout/Extra/tempmail/README.md +488 -0
  38. webscout/Extra/tempmail/__init__.py +28 -28
  39. webscout/Extra/tempmail/async_utils.py +143 -141
  40. webscout/Extra/tempmail/base.py +172 -161
  41. webscout/Extra/tempmail/cli.py +191 -187
  42. webscout/Extra/tempmail/emailnator.py +88 -84
  43. webscout/Extra/tempmail/mail_tm.py +378 -361
  44. webscout/Extra/tempmail/temp_mail_io.py +304 -292
  45. webscout/Extra/weather.py +196 -194
  46. webscout/Extra/weather_ascii.py +17 -15
  47. webscout/Provider/AISEARCH/PERPLEXED_search.py +175 -0
  48. webscout/Provider/AISEARCH/Perplexity.py +237 -304
  49. webscout/Provider/AISEARCH/README.md +106 -0
  50. webscout/Provider/AISEARCH/__init__.py +16 -10
  51. webscout/Provider/AISEARCH/brave_search.py +298 -0
  52. webscout/Provider/AISEARCH/iask_search.py +130 -209
  53. webscout/Provider/AISEARCH/monica_search.py +200 -246
  54. webscout/Provider/AISEARCH/webpilotai_search.py +242 -281
  55. webscout/Provider/Algion.py +413 -0
  56. webscout/Provider/Andi.py +74 -69
  57. webscout/Provider/Apriel.py +313 -0
  58. webscout/Provider/Ayle.py +323 -0
  59. webscout/Provider/ChatSandbox.py +329 -0
  60. webscout/Provider/ClaudeOnline.py +365 -0
  61. webscout/Provider/Cohere.py +232 -208
  62. webscout/Provider/DeepAI.py +367 -0
  63. webscout/Provider/Deepinfra.py +343 -173
  64. webscout/Provider/EssentialAI.py +217 -0
  65. webscout/Provider/ExaAI.py +274 -261
  66. webscout/Provider/Gemini.py +60 -54
  67. webscout/Provider/GithubChat.py +385 -367
  68. webscout/Provider/Gradient.py +286 -0
  69. webscout/Provider/Groq.py +556 -670
  70. webscout/Provider/HadadXYZ.py +323 -0
  71. webscout/Provider/HeckAI.py +392 -233
  72. webscout/Provider/HuggingFace.py +387 -0
  73. webscout/Provider/IBM.py +340 -0
  74. webscout/Provider/Jadve.py +317 -266
  75. webscout/Provider/K2Think.py +306 -0
  76. webscout/Provider/Koboldai.py +221 -381
  77. webscout/Provider/Netwrck.py +273 -228
  78. webscout/Provider/Nvidia.py +310 -0
  79. webscout/Provider/OPENAI/DeepAI.py +489 -0
  80. webscout/Provider/OPENAI/K2Think.py +423 -0
  81. webscout/Provider/OPENAI/PI.py +463 -0
  82. webscout/Provider/OPENAI/README.md +890 -0
  83. webscout/Provider/OPENAI/TogetherAI.py +405 -0
  84. webscout/Provider/OPENAI/TwoAI.py +255 -0
  85. webscout/Provider/OPENAI/__init__.py +148 -25
  86. webscout/Provider/OPENAI/ai4chat.py +348 -0
  87. webscout/Provider/OPENAI/akashgpt.py +436 -0
  88. webscout/Provider/OPENAI/algion.py +303 -0
  89. webscout/Provider/OPENAI/ayle.py +365 -0
  90. webscout/Provider/OPENAI/base.py +253 -46
  91. webscout/Provider/OPENAI/cerebras.py +296 -0
  92. webscout/Provider/OPENAI/chatgpt.py +514 -193
  93. webscout/Provider/OPENAI/chatsandbox.py +233 -0
  94. webscout/Provider/OPENAI/deepinfra.py +403 -272
  95. webscout/Provider/OPENAI/e2b.py +2370 -1350
  96. webscout/Provider/OPENAI/elmo.py +278 -0
  97. webscout/Provider/OPENAI/exaai.py +186 -138
  98. webscout/Provider/OPENAI/freeassist.py +446 -0
  99. webscout/Provider/OPENAI/gradient.py +448 -0
  100. webscout/Provider/OPENAI/groq.py +380 -0
  101. webscout/Provider/OPENAI/hadadxyz.py +292 -0
  102. webscout/Provider/OPENAI/heckai.py +100 -104
  103. webscout/Provider/OPENAI/huggingface.py +321 -0
  104. webscout/Provider/OPENAI/ibm.py +425 -0
  105. webscout/Provider/OPENAI/llmchat.py +253 -0
  106. webscout/Provider/OPENAI/llmchatco.py +378 -327
  107. webscout/Provider/OPENAI/meta.py +541 -0
  108. webscout/Provider/OPENAI/netwrck.py +110 -84
  109. webscout/Provider/OPENAI/nvidia.py +317 -0
  110. webscout/Provider/OPENAI/oivscode.py +348 -0
  111. webscout/Provider/OPENAI/openrouter.py +328 -0
  112. webscout/Provider/OPENAI/pydantic_imports.py +1 -0
  113. webscout/Provider/OPENAI/sambanova.py +397 -0
  114. webscout/Provider/OPENAI/sonus.py +126 -115
  115. webscout/Provider/OPENAI/textpollinations.py +218 -133
  116. webscout/Provider/OPENAI/toolbaz.py +136 -166
  117. webscout/Provider/OPENAI/typefully.py +419 -0
  118. webscout/Provider/OPENAI/typliai.py +279 -0
  119. webscout/Provider/OPENAI/utils.py +314 -211
  120. webscout/Provider/OPENAI/wisecat.py +103 -125
  121. webscout/Provider/OPENAI/writecream.py +185 -156
  122. webscout/Provider/OPENAI/x0gpt.py +227 -136
  123. webscout/Provider/OPENAI/zenmux.py +380 -0
  124. webscout/Provider/OpenRouter.py +386 -0
  125. webscout/Provider/Openai.py +337 -496
  126. webscout/Provider/PI.py +443 -344
  127. webscout/Provider/QwenLM.py +346 -254
  128. webscout/Provider/STT/__init__.py +28 -0
  129. webscout/Provider/STT/base.py +303 -0
  130. webscout/Provider/STT/elevenlabs.py +264 -0
  131. webscout/Provider/Sambanova.py +317 -0
  132. webscout/Provider/TTI/README.md +69 -0
  133. webscout/Provider/TTI/__init__.py +37 -12
  134. webscout/Provider/TTI/base.py +147 -0
  135. webscout/Provider/TTI/claudeonline.py +393 -0
  136. webscout/Provider/TTI/magicstudio.py +292 -0
  137. webscout/Provider/TTI/miragic.py +180 -0
  138. webscout/Provider/TTI/pollinations.py +331 -0
  139. webscout/Provider/TTI/together.py +334 -0
  140. webscout/Provider/TTI/utils.py +14 -0
  141. webscout/Provider/TTS/README.md +186 -0
  142. webscout/Provider/TTS/__init__.py +43 -7
  143. webscout/Provider/TTS/base.py +523 -0
  144. webscout/Provider/TTS/deepgram.py +286 -156
  145. webscout/Provider/TTS/elevenlabs.py +189 -111
  146. webscout/Provider/TTS/freetts.py +218 -0
  147. webscout/Provider/TTS/murfai.py +288 -113
  148. webscout/Provider/TTS/openai_fm.py +364 -0
  149. webscout/Provider/TTS/parler.py +203 -111
  150. webscout/Provider/TTS/qwen.py +334 -0
  151. webscout/Provider/TTS/sherpa.py +286 -0
  152. webscout/Provider/TTS/speechma.py +693 -180
  153. webscout/Provider/TTS/streamElements.py +275 -333
  154. webscout/Provider/TTS/utils.py +280 -280
  155. webscout/Provider/TextPollinationsAI.py +221 -121
  156. webscout/Provider/TogetherAI.py +450 -0
  157. webscout/Provider/TwoAI.py +309 -199
  158. webscout/Provider/TypliAI.py +311 -0
  159. webscout/Provider/UNFINISHED/ChatHub.py +219 -0
  160. webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +160 -145
  161. webscout/Provider/UNFINISHED/GizAI.py +300 -0
  162. webscout/Provider/UNFINISHED/Marcus.py +218 -0
  163. webscout/Provider/UNFINISHED/Qodo.py +481 -0
  164. webscout/Provider/UNFINISHED/XenAI.py +330 -0
  165. webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +64 -47
  166. webscout/Provider/UNFINISHED/aihumanizer.py +41 -0
  167. webscout/Provider/UNFINISHED/grammerchecker.py +37 -0
  168. webscout/Provider/UNFINISHED/liner.py +342 -0
  169. webscout/Provider/UNFINISHED/liner_api_request.py +246 -0
  170. webscout/Provider/UNFINISHED/samurai.py +231 -0
  171. webscout/Provider/WiseCat.py +256 -196
  172. webscout/Provider/WrDoChat.py +390 -0
  173. webscout/Provider/__init__.py +115 -198
  174. webscout/Provider/ai4chat.py +181 -202
  175. webscout/Provider/akashgpt.py +330 -342
  176. webscout/Provider/cerebras.py +397 -242
  177. webscout/Provider/cleeai.py +236 -213
  178. webscout/Provider/elmo.py +291 -234
  179. webscout/Provider/geminiapi.py +343 -208
  180. webscout/Provider/julius.py +245 -223
  181. webscout/Provider/learnfastai.py +333 -266
  182. webscout/Provider/llama3mitril.py +230 -180
  183. webscout/Provider/llmchat.py +308 -213
  184. webscout/Provider/llmchatco.py +321 -311
  185. webscout/Provider/meta.py +996 -794
  186. webscout/Provider/oivscode.py +332 -0
  187. webscout/Provider/searchchat.py +316 -293
  188. webscout/Provider/sonus.py +264 -208
  189. webscout/Provider/toolbaz.py +359 -320
  190. webscout/Provider/turboseek.py +332 -219
  191. webscout/Provider/typefully.py +262 -280
  192. webscout/Provider/x0gpt.py +332 -256
  193. webscout/__init__.py +31 -38
  194. webscout/__main__.py +5 -5
  195. webscout/cli.py +585 -293
  196. webscout/client.py +1497 -0
  197. webscout/conversation.py +140 -565
  198. webscout/exceptions.py +383 -339
  199. webscout/litagent/__init__.py +29 -29
  200. webscout/litagent/agent.py +492 -455
  201. webscout/litagent/constants.py +60 -60
  202. webscout/models.py +505 -181
  203. webscout/optimizers.py +32 -378
  204. webscout/prompt_manager.py +376 -274
  205. webscout/sanitize.py +1514 -0
  206. webscout/scout/README.md +452 -0
  207. webscout/scout/__init__.py +8 -8
  208. webscout/scout/core/__init__.py +7 -7
  209. webscout/scout/core/crawler.py +330 -140
  210. webscout/scout/core/scout.py +800 -568
  211. webscout/scout/core/search_result.py +51 -96
  212. webscout/scout/core/text_analyzer.py +64 -63
  213. webscout/scout/core/text_utils.py +412 -277
  214. webscout/scout/core/web_analyzer.py +54 -52
  215. webscout/scout/element.py +872 -460
  216. webscout/scout/parsers/__init__.py +70 -69
  217. webscout/scout/parsers/html5lib_parser.py +182 -172
  218. webscout/scout/parsers/html_parser.py +238 -236
  219. webscout/scout/parsers/lxml_parser.py +203 -178
  220. webscout/scout/utils.py +38 -37
  221. webscout/search/__init__.py +47 -0
  222. webscout/search/base.py +201 -0
  223. webscout/search/bing_main.py +45 -0
  224. webscout/search/brave_main.py +92 -0
  225. webscout/search/duckduckgo_main.py +57 -0
  226. webscout/search/engines/__init__.py +127 -0
  227. webscout/search/engines/bing/__init__.py +15 -0
  228. webscout/search/engines/bing/base.py +35 -0
  229. webscout/search/engines/bing/images.py +114 -0
  230. webscout/search/engines/bing/news.py +96 -0
  231. webscout/search/engines/bing/suggestions.py +36 -0
  232. webscout/search/engines/bing/text.py +109 -0
  233. webscout/search/engines/brave/__init__.py +19 -0
  234. webscout/search/engines/brave/base.py +47 -0
  235. webscout/search/engines/brave/images.py +213 -0
  236. webscout/search/engines/brave/news.py +353 -0
  237. webscout/search/engines/brave/suggestions.py +318 -0
  238. webscout/search/engines/brave/text.py +167 -0
  239. webscout/search/engines/brave/videos.py +364 -0
  240. webscout/search/engines/duckduckgo/__init__.py +25 -0
  241. webscout/search/engines/duckduckgo/answers.py +80 -0
  242. webscout/search/engines/duckduckgo/base.py +189 -0
  243. webscout/search/engines/duckduckgo/images.py +100 -0
  244. webscout/search/engines/duckduckgo/maps.py +183 -0
  245. webscout/search/engines/duckduckgo/news.py +70 -0
  246. webscout/search/engines/duckduckgo/suggestions.py +22 -0
  247. webscout/search/engines/duckduckgo/text.py +221 -0
  248. webscout/search/engines/duckduckgo/translate.py +48 -0
  249. webscout/search/engines/duckduckgo/videos.py +80 -0
  250. webscout/search/engines/duckduckgo/weather.py +84 -0
  251. webscout/search/engines/mojeek.py +61 -0
  252. webscout/search/engines/wikipedia.py +77 -0
  253. webscout/search/engines/yahoo/__init__.py +41 -0
  254. webscout/search/engines/yahoo/answers.py +19 -0
  255. webscout/search/engines/yahoo/base.py +34 -0
  256. webscout/search/engines/yahoo/images.py +323 -0
  257. webscout/search/engines/yahoo/maps.py +19 -0
  258. webscout/search/engines/yahoo/news.py +258 -0
  259. webscout/search/engines/yahoo/suggestions.py +140 -0
  260. webscout/search/engines/yahoo/text.py +273 -0
  261. webscout/search/engines/yahoo/translate.py +19 -0
  262. webscout/search/engines/yahoo/videos.py +302 -0
  263. webscout/search/engines/yahoo/weather.py +220 -0
  264. webscout/search/engines/yandex.py +67 -0
  265. webscout/search/engines/yep/__init__.py +13 -0
  266. webscout/search/engines/yep/base.py +34 -0
  267. webscout/search/engines/yep/images.py +101 -0
  268. webscout/search/engines/yep/suggestions.py +38 -0
  269. webscout/search/engines/yep/text.py +99 -0
  270. webscout/search/http_client.py +172 -0
  271. webscout/search/results.py +141 -0
  272. webscout/search/yahoo_main.py +57 -0
  273. webscout/search/yep_main.py +48 -0
  274. webscout/server/__init__.py +48 -0
  275. webscout/server/config.py +78 -0
  276. webscout/server/exceptions.py +69 -0
  277. webscout/server/providers.py +286 -0
  278. webscout/server/request_models.py +131 -0
  279. webscout/server/request_processing.py +404 -0
  280. webscout/server/routes.py +642 -0
  281. webscout/server/server.py +351 -0
  282. webscout/server/ui_templates.py +1171 -0
  283. webscout/swiftcli/__init__.py +79 -809
  284. webscout/swiftcli/core/__init__.py +7 -0
  285. webscout/swiftcli/core/cli.py +574 -0
  286. webscout/swiftcli/core/context.py +98 -0
  287. webscout/swiftcli/core/group.py +268 -0
  288. webscout/swiftcli/decorators/__init__.py +28 -0
  289. webscout/swiftcli/decorators/command.py +243 -0
  290. webscout/swiftcli/decorators/options.py +247 -0
  291. webscout/swiftcli/decorators/output.py +392 -0
  292. webscout/swiftcli/exceptions.py +21 -0
  293. webscout/swiftcli/plugins/__init__.py +9 -0
  294. webscout/swiftcli/plugins/base.py +134 -0
  295. webscout/swiftcli/plugins/manager.py +269 -0
  296. webscout/swiftcli/utils/__init__.py +58 -0
  297. webscout/swiftcli/utils/formatting.py +251 -0
  298. webscout/swiftcli/utils/parsing.py +368 -0
  299. webscout/update_checker.py +280 -136
  300. webscout/utils.py +28 -14
  301. webscout/version.py +2 -1
  302. webscout/version.py.bak +3 -0
  303. webscout/zeroart/__init__.py +218 -55
  304. webscout/zeroart/base.py +70 -60
  305. webscout/zeroart/effects.py +155 -99
  306. webscout/zeroart/fonts.py +1799 -816
  307. webscout-2026.1.19.dist-info/METADATA +638 -0
  308. webscout-2026.1.19.dist-info/RECORD +312 -0
  309. {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
  310. webscout-2026.1.19.dist-info/entry_points.txt +4 -0
  311. webscout-2026.1.19.dist-info/top_level.txt +1 -0
  312. inferno/__init__.py +0 -6
  313. inferno/__main__.py +0 -9
  314. inferno/cli.py +0 -6
  315. webscout/DWEBS.py +0 -477
  316. webscout/Extra/autocoder/__init__.py +0 -9
  317. webscout/Extra/autocoder/autocoder.py +0 -849
  318. webscout/Extra/autocoder/autocoder_utiles.py +0 -332
  319. webscout/LLM.py +0 -442
  320. webscout/Litlogger/__init__.py +0 -67
  321. webscout/Litlogger/core/__init__.py +0 -6
  322. webscout/Litlogger/core/level.py +0 -23
  323. webscout/Litlogger/core/logger.py +0 -165
  324. webscout/Litlogger/handlers/__init__.py +0 -12
  325. webscout/Litlogger/handlers/console.py +0 -33
  326. webscout/Litlogger/handlers/file.py +0 -143
  327. webscout/Litlogger/handlers/network.py +0 -173
  328. webscout/Litlogger/styles/__init__.py +0 -7
  329. webscout/Litlogger/styles/colors.py +0 -249
  330. webscout/Litlogger/styles/formats.py +0 -458
  331. webscout/Litlogger/styles/text.py +0 -87
  332. webscout/Litlogger/utils/__init__.py +0 -6
  333. webscout/Litlogger/utils/detectors.py +0 -153
  334. webscout/Litlogger/utils/formatters.py +0 -200
  335. webscout/Local/__init__.py +0 -12
  336. webscout/Local/__main__.py +0 -9
  337. webscout/Local/api.py +0 -576
  338. webscout/Local/cli.py +0 -516
  339. webscout/Local/config.py +0 -75
  340. webscout/Local/llm.py +0 -287
  341. webscout/Local/model_manager.py +0 -253
  342. webscout/Local/server.py +0 -721
  343. webscout/Local/utils.py +0 -93
  344. webscout/Provider/AI21.py +0 -177
  345. webscout/Provider/AISEARCH/DeepFind.py +0 -250
  346. webscout/Provider/AISEARCH/ISou.py +0 -256
  347. webscout/Provider/AISEARCH/felo_search.py +0 -228
  348. webscout/Provider/AISEARCH/genspark_search.py +0 -208
  349. webscout/Provider/AISEARCH/hika_search.py +0 -194
  350. webscout/Provider/AISEARCH/scira_search.py +0 -324
  351. webscout/Provider/Aitopia.py +0 -292
  352. webscout/Provider/AllenAI.py +0 -413
  353. webscout/Provider/Blackboxai.py +0 -229
  354. webscout/Provider/C4ai.py +0 -432
  355. webscout/Provider/ChatGPTClone.py +0 -226
  356. webscout/Provider/ChatGPTES.py +0 -237
  357. webscout/Provider/ChatGPTGratis.py +0 -194
  358. webscout/Provider/Chatify.py +0 -175
  359. webscout/Provider/Cloudflare.py +0 -273
  360. webscout/Provider/DeepSeek.py +0 -196
  361. webscout/Provider/ElectronHub.py +0 -709
  362. webscout/Provider/ExaChat.py +0 -342
  363. webscout/Provider/Free2GPT.py +0 -241
  364. webscout/Provider/GPTWeb.py +0 -193
  365. webscout/Provider/Glider.py +0 -211
  366. webscout/Provider/HF_space/__init__.py +0 -0
  367. webscout/Provider/HF_space/qwen_qwen2.py +0 -206
  368. webscout/Provider/HuggingFaceChat.py +0 -462
  369. webscout/Provider/Hunyuan.py +0 -272
  370. webscout/Provider/LambdaChat.py +0 -392
  371. webscout/Provider/Llama.py +0 -200
  372. webscout/Provider/Llama3.py +0 -204
  373. webscout/Provider/Marcus.py +0 -148
  374. webscout/Provider/OLLAMA.py +0 -396
  375. webscout/Provider/OPENAI/c4ai.py +0 -367
  376. webscout/Provider/OPENAI/chatgptclone.py +0 -460
  377. webscout/Provider/OPENAI/exachat.py +0 -433
  378. webscout/Provider/OPENAI/freeaichat.py +0 -352
  379. webscout/Provider/OPENAI/opkfc.py +0 -488
  380. webscout/Provider/OPENAI/scirachat.py +0 -463
  381. webscout/Provider/OPENAI/standardinput.py +0 -425
  382. webscout/Provider/OPENAI/typegpt.py +0 -346
  383. webscout/Provider/OPENAI/uncovrAI.py +0 -455
  384. webscout/Provider/OPENAI/venice.py +0 -413
  385. webscout/Provider/OPENAI/yep.py +0 -327
  386. webscout/Provider/OpenGPT.py +0 -199
  387. webscout/Provider/Perplexitylabs.py +0 -415
  388. webscout/Provider/Phind.py +0 -535
  389. webscout/Provider/PizzaGPT.py +0 -198
  390. webscout/Provider/Reka.py +0 -214
  391. webscout/Provider/StandardInput.py +0 -278
  392. webscout/Provider/TTI/AiForce/__init__.py +0 -22
  393. webscout/Provider/TTI/AiForce/async_aiforce.py +0 -224
  394. webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -245
  395. webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -9
  396. webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -181
  397. webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -180
  398. webscout/Provider/TTI/ImgSys/__init__.py +0 -23
  399. webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -202
  400. webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -195
  401. webscout/Provider/TTI/MagicStudio/__init__.py +0 -2
  402. webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -111
  403. webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -109
  404. webscout/Provider/TTI/Nexra/__init__.py +0 -22
  405. webscout/Provider/TTI/Nexra/async_nexra.py +0 -286
  406. webscout/Provider/TTI/Nexra/sync_nexra.py +0 -258
  407. webscout/Provider/TTI/PollinationsAI/__init__.py +0 -23
  408. webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -311
  409. webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -265
  410. webscout/Provider/TTI/aiarta/__init__.py +0 -2
  411. webscout/Provider/TTI/aiarta/async_aiarta.py +0 -482
  412. webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -440
  413. webscout/Provider/TTI/artbit/__init__.py +0 -22
  414. webscout/Provider/TTI/artbit/async_artbit.py +0 -155
  415. webscout/Provider/TTI/artbit/sync_artbit.py +0 -148
  416. webscout/Provider/TTI/fastflux/__init__.py +0 -22
  417. webscout/Provider/TTI/fastflux/async_fastflux.py +0 -261
  418. webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -252
  419. webscout/Provider/TTI/huggingface/__init__.py +0 -22
  420. webscout/Provider/TTI/huggingface/async_huggingface.py +0 -199
  421. webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -195
  422. webscout/Provider/TTI/piclumen/__init__.py +0 -23
  423. webscout/Provider/TTI/piclumen/async_piclumen.py +0 -268
  424. webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -233
  425. webscout/Provider/TTI/pixelmuse/__init__.py +0 -4
  426. webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -249
  427. webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -182
  428. webscout/Provider/TTI/talkai/__init__.py +0 -4
  429. webscout/Provider/TTI/talkai/async_talkai.py +0 -229
  430. webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
  431. webscout/Provider/TTS/gesserit.py +0 -127
  432. webscout/Provider/TeachAnything.py +0 -187
  433. webscout/Provider/Venice.py +0 -219
  434. webscout/Provider/VercelAI.py +0 -234
  435. webscout/Provider/WebSim.py +0 -228
  436. webscout/Provider/Writecream.py +0 -211
  437. webscout/Provider/WritingMate.py +0 -197
  438. webscout/Provider/aimathgpt.py +0 -189
  439. webscout/Provider/askmyai.py +0 -158
  440. webscout/Provider/asksteve.py +0 -203
  441. webscout/Provider/bagoodex.py +0 -145
  442. webscout/Provider/chatglm.py +0 -205
  443. webscout/Provider/copilot.py +0 -428
  444. webscout/Provider/freeaichat.py +0 -271
  445. webscout/Provider/gaurish.py +0 -244
  446. webscout/Provider/geminiprorealtime.py +0 -160
  447. webscout/Provider/granite.py +0 -187
  448. webscout/Provider/hermes.py +0 -219
  449. webscout/Provider/koala.py +0 -268
  450. webscout/Provider/labyrinth.py +0 -340
  451. webscout/Provider/lepton.py +0 -194
  452. webscout/Provider/llamatutor.py +0 -192
  453. webscout/Provider/multichat.py +0 -325
  454. webscout/Provider/promptrefine.py +0 -193
  455. webscout/Provider/scira_chat.py +0 -277
  456. webscout/Provider/scnet.py +0 -187
  457. webscout/Provider/talkai.py +0 -194
  458. webscout/Provider/tutorai.py +0 -252
  459. webscout/Provider/typegpt.py +0 -232
  460. webscout/Provider/uncovr.py +0 -312
  461. webscout/Provider/yep.py +0 -376
  462. webscout/litprinter/__init__.py +0 -59
  463. webscout/scout/core.py +0 -881
  464. webscout/tempid.py +0 -128
  465. webscout/webscout_search.py +0 -1346
  466. webscout/webscout_search_async.py +0 -877
  467. webscout/yep_search.py +0 -297
  468. webscout-8.2.2.dist-info/METADATA +0 -734
  469. webscout-8.2.2.dist-info/RECORD +0 -309
  470. webscout-8.2.2.dist-info/entry_points.txt +0 -5
  471. webscout-8.2.2.dist-info/top_level.txt +0 -3
  472. webstoken/__init__.py +0 -30
  473. webstoken/classifier.py +0 -189
  474. webstoken/keywords.py +0 -216
  475. webstoken/language.py +0 -128
  476. webstoken/ner.py +0 -164
  477. webstoken/normalizer.py +0 -35
  478. webstoken/processor.py +0 -77
  479. webstoken/sentiment.py +0 -206
  480. webstoken/stemmer.py +0 -73
  481. webstoken/tagger.py +0 -60
  482. webstoken/tokenizer.py +0 -158
  483. {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info/licenses}/LICENSE.md +0 -0
@@ -0,0 +1,7 @@
1
+ """Core functionality for SwiftCLI."""
2
+
3
+ from .cli import CLI
4
+ from .context import Context
5
+ from .group import Group
6
+
7
+ __all__ = ['CLI', 'Context', 'Group']
@@ -0,0 +1,574 @@
1
+ """Main CLI application class."""
2
+
3
+ import sys
4
+ from typing import Any, Dict, List, Optional, cast
5
+
6
+ from rich.console import Console
7
+
8
+ from ..exceptions import UsageError
9
+ from ..plugins.manager import PluginManager
10
+ from ..utils.formatting import format_error
11
+ from .context import Context
12
+ from .group import Group # Fix: Import Group for type checking and usage
13
+
14
+ console = Console()
15
+
16
+
17
+ class CLI:
18
+ """
19
+ Main CLI application class.
20
+
21
+ The CLI class is the core of SwiftCLI. It handles command registration,
22
+ argument parsing, and command execution. It also manages plugins and
23
+ provides the main entry point for CLI applications.
24
+
25
+ Attributes:
26
+ name: Application name
27
+ help: Application description
28
+ version: Application version
29
+ debug: Debug mode flag
30
+ commands: Registered commands
31
+ groups: Command groups
32
+ plugin_manager: Plugin manager instance
33
+
34
+ Example:
35
+ >>> app = CLI(name="myapp", version="1.0.0")
36
+ >>> @app.command()
37
+ ... def greet(name: str):
38
+ ... '''Greet someone'''
39
+ ... print(f"Hello {name}!")
40
+ >>> app.run()
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ name: str,
46
+ help: Optional[str] = None,
47
+ version: Optional[str] = None,
48
+ debug: bool = False,
49
+ ):
50
+ """
51
+ Initialize CLI application.
52
+
53
+ Args:
54
+ name: Application name
55
+ help: Application description
56
+ version: Application version
57
+ debug: Enable debug mode
58
+ """
59
+ self.name = name
60
+ self.help = help
61
+ self.version = version
62
+ self.debug = debug
63
+
64
+ self.commands: Dict[str, Dict[str, Any]] = {}
65
+ self.groups: Dict[str, "Group"] = {}
66
+ self.command_aliases: Dict[str, str] = {}
67
+ self.command_chain: bool = False
68
+ self.plugin_manager = PluginManager()
69
+
70
+ # Initialize plugin manager with this CLI instance
71
+ self.plugin_manager.init_plugins(self)
72
+
73
+ def command(
74
+ self,
75
+ name: Optional[str] = None,
76
+ help: Optional[str] = None,
77
+ aliases: Optional[List[str]] = None,
78
+ hidden: bool = False,
79
+ ):
80
+ """
81
+ Decorator to register a command.
82
+
83
+ Args:
84
+ name: Command name (defaults to function name)
85
+ help: Command help text
86
+ aliases: Alternative command names
87
+ hidden: Hide from help output
88
+
89
+ Example:
90
+ @app.command()
91
+ def hello(name: str):
92
+ '''Say hello'''
93
+ print(f"Hello {name}!")
94
+ """
95
+
96
+ def decorator(f):
97
+ cmd_name = name or f.__name__
98
+ self.commands[cmd_name] = {
99
+ "name": cmd_name,
100
+ "func": f,
101
+ "help": help or f.__doc__,
102
+ "aliases": aliases or [],
103
+ "hidden": hidden,
104
+ }
105
+
106
+ # Register aliases
107
+ for alias in aliases or []:
108
+ self.commands[alias] = self.commands[cmd_name]
109
+
110
+ return f
111
+
112
+ return decorator
113
+
114
+ def group(self, name: Optional[str] = None, help: Optional[str] = None, **kwargs):
115
+ """
116
+ Create a command group.
117
+
118
+ Args:
119
+ name: Group name
120
+ help: Group help text
121
+ **kwargs: Additional group options
122
+
123
+ Example:
124
+ @app.group()
125
+ def db():
126
+ '''Database commands'''
127
+ pass
128
+
129
+ @db.command()
130
+ def migrate():
131
+ '''Run migrations'''
132
+ pass
133
+ """
134
+ # Group is now imported at the top
135
+
136
+ def decorator(f):
137
+ group_name = name or f.__name__
138
+ group = Group(name=group_name, help=help or f.__doc__, parent=self, **kwargs)
139
+ self.groups[group_name] = group
140
+ return group
141
+
142
+ return decorator
143
+
144
+ def alias(self, command_name: str, alias_name: str) -> None:
145
+ """
146
+ Add a command alias.
147
+
148
+ Args:
149
+ command_name: Original command name
150
+ alias_name: Alias name
151
+
152
+ Example:
153
+ app.alias("list", "ls")
154
+ """
155
+ if command_name in self.commands:
156
+ self.command_aliases[alias_name] = command_name
157
+ else:
158
+ raise UsageError(f"Command {command_name} not found")
159
+
160
+ def enable_chaining(self, enabled: bool = True) -> None:
161
+ """
162
+ Enable or disable command chaining.
163
+
164
+ Args:
165
+ enabled: Whether to enable chaining
166
+
167
+ Example:
168
+ app.enable_chaining(True)
169
+ """
170
+ self.command_chain = enabled
171
+
172
+ def run(self, args: Optional[List[str]] = None) -> int:
173
+ """
174
+ Run the CLI application.
175
+
176
+ Args:
177
+ args: Command line arguments (defaults to sys.argv[1:])
178
+
179
+ Returns:
180
+ Exit code (0 for success, non-zero for error)
181
+ """
182
+ try:
183
+ args = args or sys.argv[1:]
184
+
185
+ # Show help if no arguments
186
+ if not args or args[0] in ["-h", "--help"]:
187
+ self._print_help()
188
+ return 0
189
+
190
+ # Show version if requested
191
+ if args[0] in ["-v", "--version"] and self.version:
192
+ console.print(self.version)
193
+ return 0
194
+
195
+ command_name = args[0]
196
+ command_args = args[1:]
197
+
198
+ # Check if it's a command alias
199
+ if command_name in self.command_aliases:
200
+ command_name = self.command_aliases[command_name]
201
+
202
+ # Check if it's a group command
203
+ if command_name in self.groups:
204
+ return self.groups[command_name].run(command_args)
205
+
206
+ # Check if it's a regular command
207
+ if command_name not in self.commands:
208
+ format_error(f"Unknown command: {command_name}")
209
+ self._print_help()
210
+ return 1
211
+
212
+ # Create command context
213
+ ctx = Context(self, command=command_name, debug=self.debug)
214
+
215
+ # Run command through plugin system
216
+ if not self.plugin_manager.before_command(command_name, command_args):
217
+ return 1
218
+
219
+ try:
220
+ import asyncio
221
+ import inspect
222
+
223
+ command = self.commands[command_name]
224
+ func = command["func"]
225
+ params = self._parse_args(command, command_args)
226
+
227
+ # Inject context if function was decorated with pass_context
228
+ if getattr(func, "_pass_context", False):
229
+ # Call with ctx as first positional arg
230
+ call_args = (ctx,)
231
+ else:
232
+ call_args = ()
233
+
234
+ # If coroutine function, run it using asyncio
235
+ if inspect.iscoroutinefunction(func):
236
+ result = asyncio.run(func(*call_args, **params))
237
+ else:
238
+ result = func(*call_args, **params)
239
+
240
+ # If function returned a coroutine (in case wrapper returned coroutine)
241
+ if not inspect.iscoroutine(result) and hasattr(result, "__await__"):
242
+ # awaitable returned
243
+ result = asyncio.run(result)
244
+
245
+ self.plugin_manager.after_command(command_name, command_args, result)
246
+ return 0
247
+ except Exception as e:
248
+ self.plugin_manager.on_error(command_name, e)
249
+ if self.debug:
250
+ raise
251
+ format_error(str(e))
252
+ return 1
253
+
254
+ except KeyboardInterrupt:
255
+ console.print("\nOperation cancelled by user")
256
+ return 130
257
+ except Exception as e:
258
+ if self.debug:
259
+ raise
260
+ format_error(str(e))
261
+ return 1
262
+
263
+ def generate_completion_script(self, shell: str = "bash") -> str:
264
+ """
265
+ Generate shell completion script.
266
+
267
+ Args:
268
+ shell: Shell type (bash, zsh, fish)
269
+
270
+ Returns:
271
+ Completion script as string
272
+
273
+ Example:
274
+ script = app.generate_completion_script('bash')
275
+ print(script)
276
+ """
277
+ if shell == "bash":
278
+ return self._generate_bash_completion()
279
+ elif shell == "zsh":
280
+ return self._generate_zsh_completion()
281
+ elif shell == "fish":
282
+ return self._generate_fish_completion()
283
+ else:
284
+ raise UsageError(f"Unsupported shell: {shell}")
285
+
286
+ def _generate_bash_completion(self) -> str:
287
+ """Generate bash completion script."""
288
+ commands = []
289
+ for cmd_name, cmd in self.commands.items():
290
+ if not cmd.get("hidden", False):
291
+ commands.append(cmd_name)
292
+ if "aliases" in cmd:
293
+ commands.extend(cmd["aliases"])
294
+
295
+ for group_name in self.groups:
296
+ commands.append(group_name)
297
+
298
+ script = f"""#!/bin/bash
299
+ # Bash completion for {self.name}
300
+
301
+ _{self.name}_completion() {{
302
+ local cur prev words cword
303
+ _init_completion || return
304
+
305
+ # Generate completion options
306
+ COMPREPLY=($(compgen -W "{" ".join(commands)}" -- "$cur"))
307
+ }}
308
+
309
+ complete -F _{self.name}_completion {self.name}
310
+ """
311
+ return script
312
+
313
+ def _generate_zsh_completion(self) -> str:
314
+ """Generate zsh completion script."""
315
+ commands = []
316
+ for cmd_name, cmd in self.commands.items():
317
+ if not cmd.get("hidden", False):
318
+ commands.append(cmd_name)
319
+ if "aliases" in cmd:
320
+ commands.extend(cmd["aliases"])
321
+
322
+ for group_name in self.groups:
323
+ commands.append(group_name)
324
+
325
+ script = f"""#compdef {self.name}
326
+
327
+ local -a commands
328
+ commands=({" ".join(commands)})
329
+
330
+ _arguments \
331
+ '1: :->cmds' \
332
+ '*::arg:->args'
333
+
334
+ case $state in
335
+ cmds)
336
+ _describe 'command' commands
337
+ ;;
338
+ args)
339
+ # Add argument completion here if needed
340
+ ;;
341
+ esac
342
+ """
343
+ return script
344
+
345
+ def _generate_fish_completion(self) -> str:
346
+ """Generate fish completion script."""
347
+ commands = []
348
+ for cmd_name, cmd in self.commands.items():
349
+ if not cmd.get("hidden", False):
350
+ commands.append(cmd_name)
351
+ if "aliases" in cmd:
352
+ commands.extend(cmd["aliases"])
353
+
354
+ for group_name in self.groups:
355
+ commands.append(group_name)
356
+
357
+ script = f"""# Fish completion for {self.name}
358
+
359
+ complete -c {self.name} -n "__fish_use_subcommand" -a "{" ".join(commands)}"
360
+ """
361
+ return script
362
+
363
+ def _parse_args(self, command: Dict[str, Any], args: List[str]) -> Dict[str, Any]:
364
+ """Parse command arguments."""
365
+ from ..utils.parsing import (
366
+ check_mutually_exclusive,
367
+ convert_type,
368
+ get_env_var,
369
+ parse_args,
370
+ validate_argument,
371
+ validate_choice,
372
+ )
373
+
374
+ params = {}
375
+ func = command["func"]
376
+
377
+ # Collect mutually exclusive groups
378
+ exclusive_groups = []
379
+
380
+ # Parse command-line arguments
381
+ parsed_args = parse_args(args)
382
+
383
+ # Handle options
384
+ if hasattr(func, "_options"):
385
+ for opt in func._options:
386
+ # Use the longest parameter name (usually the --long-form) for the parameter name
387
+ param_names = [p.lstrip("-").replace("-", "_") for p in opt["param_decls"]]
388
+ name = cast(str, max(param_names, key=len)) # Use the longest name
389
+
390
+ # Check all possible parameter names in parsed args
391
+ value = None
392
+ found = False
393
+ for param_name in param_names:
394
+ if param_name in parsed_args:
395
+ value = parsed_args[param_name]
396
+ found = True
397
+ break
398
+
399
+ if found:
400
+ # Handle 'count' option (e.g., -v, -vv)
401
+ if opt.get("count", False):
402
+ if isinstance(value, list):
403
+ params[name] = len(value)
404
+ elif isinstance(value, bool):
405
+ params[name] = 1 if value else 0
406
+ elif value is not None:
407
+ try:
408
+ params[name] = int(value)
409
+ except Exception:
410
+ params[name] = 1
411
+ else:
412
+ params[name] = 1
413
+ # Handle 'multiple' option which collects multiple values
414
+ elif opt.get("multiple", False):
415
+ items = value if isinstance(value, list) else [value]
416
+ if "type" in opt:
417
+ items = [convert_type(str(v), opt["type"], name) for v in items if v is not None]
418
+ if "choices" in opt and opt["choices"]:
419
+ for v in items:
420
+ validate_choice(
421
+ str(v), opt["choices"], name, opt.get("case_sensitive", True)
422
+ )
423
+ params[name] = items
424
+ else:
425
+ # Normal option/flag handling
426
+ # If multiple values found but option is not 'multiple', take last
427
+ if isinstance(value, list):
428
+ value_to_convert = value[-1]
429
+ else:
430
+ value_to_convert = value
431
+
432
+ if opt.get("is_flag", False):
433
+ # Flags are boolean; if a string value is provided, attempt to convert
434
+ if isinstance(value_to_convert, str):
435
+ # If 'type' is provided and is bool, convert accordingly
436
+ if "type" in opt and opt["type"] is bool:
437
+ value_to_convert = convert_type(value_to_convert, bool, name)
438
+ else:
439
+ value_to_convert = True
440
+ elif isinstance(value_to_convert, bool):
441
+ # Use boolean value
442
+ value_to_convert = value_to_convert
443
+ elif value_to_convert is not None:
444
+ # Non-boolean provided, try convert to bool
445
+ value_to_convert = convert_type(str(value_to_convert), bool, name)
446
+ else:
447
+ value_to_convert = False
448
+
449
+ if "type" in opt and not opt.get("is_flag", False):
450
+ value_to_convert = convert_type(str(value_to_convert), opt["type"], name) if value_to_convert is not None else None
451
+ if "choices" in opt and opt["choices"]:
452
+ if value_to_convert is not None:
453
+ validate_choice(
454
+ str(value_to_convert),
455
+ opt["choices"],
456
+ name,
457
+ opt.get("case_sensitive", True),
458
+ )
459
+
460
+ # Apply validation rules
461
+ if opt.get("validation") and value_to_convert is not None:
462
+ value_to_convert = validate_argument(
463
+ str(value_to_convert), opt["validation"], name
464
+ )
465
+
466
+ params[name] = value_to_convert
467
+ # Apply callback if provided
468
+ if opt.get("callback") and callable(opt.get("callback")):
469
+ params[name] = opt.get("callback")(params[name])
470
+
471
+ # Collect mutually exclusive groups
472
+ if opt.get("mutually_exclusive"):
473
+ exclusive_groups.append(opt["mutually_exclusive"])
474
+ elif opt.get("required", False):
475
+ raise UsageError(f"Missing required option: {name}")
476
+ elif "default" in opt:
477
+ params[name] = opt["default"]
478
+
479
+ # Handle arguments
480
+ if hasattr(func, "_arguments"):
481
+ for i, arg in enumerate(func._arguments):
482
+ name = arg["name"]
483
+ if f"arg{i}" in parsed_args:
484
+ value = parsed_args[f"arg{i}"]
485
+ if "type" in arg:
486
+ value = convert_type(value, arg["type"], name)
487
+
488
+ # Apply validation rules
489
+ if arg.get("validation"):
490
+ value = validate_argument(value, arg["validation"], name)
491
+
492
+ params[name] = value
493
+
494
+ # Collect mutually exclusive groups
495
+ if arg.get("mutually_exclusive"):
496
+ exclusive_groups.append(arg["mutually_exclusive"])
497
+ elif arg.get("required", True):
498
+ raise UsageError(f"Missing required argument: {name}")
499
+ elif "default" in arg:
500
+ params[name] = arg["default"]
501
+
502
+ # Check mutually exclusive options
503
+ if exclusive_groups:
504
+ check_mutually_exclusive(params, exclusive_groups)
505
+
506
+ # Handle environment variables
507
+ if hasattr(func, "_envvars"):
508
+ for env in func._envvars:
509
+ name = env["name"].lower()
510
+ value = get_env_var(
511
+ env["name"],
512
+ env.get("type", str),
513
+ env.get("required", False),
514
+ env.get("default"),
515
+ )
516
+ if value is not None:
517
+ params[name] = value
518
+
519
+ return params
520
+
521
+ def _print_help(self) -> None:
522
+ """Print application help message."""
523
+ console.print(f"\n[bold]{self.name}[/]")
524
+ if self.help:
525
+ console.print(f"\n{self.help}")
526
+
527
+ # Show commands
528
+ console.print("\n[bold]Commands:[/]")
529
+ printed = set()
530
+ for name, cmd in self.commands.items():
531
+ primary = cmd.get("name", name)
532
+ if primary in printed:
533
+ continue
534
+ printed.add(primary)
535
+ if not cmd.get("hidden", False):
536
+ aliases = cmd.get("aliases", [])
537
+ alias_text = f" (aliases: {', '.join(aliases)})" if aliases else ""
538
+ console.print(f" {primary:20} {cmd['help'] or ''}{alias_text}")
539
+
540
+ # Show command groups
541
+ for name, group in self.groups.items():
542
+ console.print(f"\n[bold]{name} commands:[/]")
543
+ printed_group = set()
544
+ for cmd_name, cmd in group.commands.items():
545
+ # cmd can be Group or dict
546
+ if isinstance(cmd, dict):
547
+ primary = cmd.get("name", cmd_name)
548
+ elif hasattr(cmd, "name"):
549
+ primary = cmd.name
550
+ else:
551
+ primary = cmd_name
552
+ if primary in printed_group:
553
+ continue
554
+ printed_group.add(primary)
555
+ # Get help and hidden
556
+ help_text = ""
557
+ hidden = False
558
+ aliases = []
559
+ if isinstance(cmd, dict):
560
+ hidden = cmd.get("hidden", False)
561
+ help_text = cmd.get("help", "")
562
+ aliases = cmd.get("aliases", [])
563
+ elif isinstance(cmd, Group):
564
+ help_text = cmd.help or ""
565
+ if not hidden:
566
+ alias_text = f" (aliases: {', '.join(aliases)})" if aliases else ""
567
+ console.print(f" {primary:20} {help_text}{alias_text}")
568
+
569
+ console.print("\nUse -h or --help with any command for more info")
570
+ if self.version:
571
+ console.print("Use -v or --version to show version")
572
+
573
+ def __repr__(self) -> str:
574
+ return f"<CLI name={self.name}>"
@@ -0,0 +1,98 @@
1
+ """Context handling for SwiftCLI."""
2
+
3
+ from typing import TYPE_CHECKING, Any, Dict, Optional
4
+
5
+ if TYPE_CHECKING:
6
+ from .cli import CLI
7
+
8
+
9
+ class Context:
10
+ """
11
+ Context object that holds state for the CLI app.
12
+
13
+ The Context class provides access to the CLI application instance and maintains
14
+ state throughout command execution. It can be used to pass data between
15
+ commands and access global configuration.
16
+
17
+ Attributes:
18
+ cli: The CLI application instance.
19
+ parent: The parent context if this is a subcommand.
20
+ command: The current command name.
21
+ obj: An object that can be used to store arbitrary data.
22
+ params: Dictionary of current command parameters.
23
+ debug: Debug mode flag.
24
+
25
+ Example:
26
+ @app.command()
27
+ @pass_context
28
+ def status(ctx):
29
+ '''Show application status'''
30
+ print(f"App: {ctx.cli.name}")
31
+ print(f"Debug: {ctx.debug}")
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ cli: Optional["CLI"] = None,
37
+ parent: Optional["Context"] = None,
38
+ command: Optional[str] = None,
39
+ obj: Any = None,
40
+ debug: bool = False,
41
+ ):
42
+ self.cli = cli
43
+ self.parent = parent
44
+ self.command = command
45
+ self.obj = obj
46
+ self.params: Dict[str, Any] = {}
47
+ self.debug = debug
48
+
49
+ def get_parameter(self, name: str, default: Any = None) -> Any:
50
+ """
51
+ Get a parameter value from the context.
52
+
53
+ Args:
54
+ name: Parameter name
55
+ default: Default value if parameter not found
56
+
57
+ Returns:
58
+ Parameter value or default
59
+ """
60
+ return self.params.get(name, default)
61
+
62
+ def set_parameter(self, name: str, value: Any) -> None:
63
+ """
64
+ Set a parameter value in the context.
65
+
66
+ Args:
67
+ name: Parameter name
68
+ value: Parameter value
69
+ """
70
+ self.params[name] = value
71
+
72
+ def get_parent_context(self) -> Optional["Context"]:
73
+ """Get the parent context if it exists."""
74
+ return self.parent
75
+
76
+ def create_child_context(self, command: Optional[str] = None, obj: Any = None) -> "Context":
77
+ """
78
+ Create a new child context.
79
+
80
+ Args:
81
+ command: Command name for the child context
82
+ obj: Object to store in child context
83
+
84
+ Returns:
85
+ New child context
86
+ """
87
+ return Context(cli=self.cli, parent=self, command=command, obj=obj, debug=self.debug)
88
+
89
+ @property
90
+ def root_context(self) -> "Context":
91
+ """Get the root context by traversing up the parent chain."""
92
+ ctx = self
93
+ while ctx.parent is not None:
94
+ ctx = ctx.parent
95
+ return ctx
96
+
97
+ def __repr__(self) -> str:
98
+ return f"<Context command={self.command}>"