webscout 8.2.6__py3-none-any.whl → 8.2.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of webscout might be problematic. Click here for more details.
- webscout/AIutel.py +97 -87
- webscout/version.py +1 -1
- {webscout-8.2.6.dist-info → webscout-8.2.7.dist-info}/METADATA +2 -15
- webscout-8.2.7.dist-info/RECORD +26 -0
- {webscout-8.2.6.dist-info → webscout-8.2.7.dist-info}/WHEEL +1 -1
- webscout-8.2.7.dist-info/entry_points.txt +3 -0
- webscout-8.2.7.dist-info/top_level.txt +1 -0
- webscout/Extra/GitToolkit/__init__.py +0 -10
- webscout/Extra/GitToolkit/gitapi/__init__.py +0 -12
- webscout/Extra/GitToolkit/gitapi/repository.py +0 -195
- webscout/Extra/GitToolkit/gitapi/user.py +0 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +0 -62
- webscout/Extra/YTToolkit/YTdownloader.py +0 -957
- webscout/Extra/YTToolkit/__init__.py +0 -3
- webscout/Extra/YTToolkit/transcriber.py +0 -476
- webscout/Extra/YTToolkit/ytapi/__init__.py +0 -6
- webscout/Extra/YTToolkit/ytapi/channel.py +0 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +0 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +0 -45
- webscout/Extra/YTToolkit/ytapi/https.py +0 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +0 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +0 -59
- webscout/Extra/YTToolkit/ytapi/pool.py +0 -8
- webscout/Extra/YTToolkit/ytapi/query.py +0 -40
- webscout/Extra/YTToolkit/ytapi/stream.py +0 -63
- webscout/Extra/YTToolkit/ytapi/utils.py +0 -62
- webscout/Extra/YTToolkit/ytapi/video.py +0 -232
- webscout/Extra/__init__.py +0 -7
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -910
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/Extra/gguf.py +0 -684
- webscout/Extra/tempmail/__init__.py +0 -28
- webscout/Extra/tempmail/async_utils.py +0 -141
- webscout/Extra/tempmail/base.py +0 -161
- webscout/Extra/tempmail/cli.py +0 -187
- webscout/Extra/tempmail/emailnator.py +0 -84
- webscout/Extra/tempmail/mail_tm.py +0 -361
- webscout/Extra/tempmail/temp_mail_io.py +0 -292
- webscout/Extra/weather.py +0 -194
- webscout/Extra/weather_ascii.py +0 -76
- 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/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -250
- webscout/Provider/AISEARCH/ISou.py +0 -256
- webscout/Provider/AISEARCH/Perplexity.py +0 -359
- webscout/Provider/AISEARCH/__init__.py +0 -10
- webscout/Provider/AISEARCH/felo_search.py +0 -228
- webscout/Provider/AISEARCH/genspark_search.py +0 -208
- webscout/Provider/AISEARCH/hika_search.py +0 -198
- webscout/Provider/AISEARCH/iask_search.py +0 -436
- webscout/Provider/AISEARCH/monica_search.py +0 -246
- webscout/Provider/AISEARCH/scira_search.py +0 -322
- webscout/Provider/AISEARCH/webpilotai_search.py +0 -281
- webscout/Provider/Aitopia.py +0 -316
- webscout/Provider/AllenAI.py +0 -447
- webscout/Provider/Andi.py +0 -228
- webscout/Provider/Blackboxai.py +0 -229
- webscout/Provider/ChatGPTClone.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/ChatSandbox.py +0 -342
- webscout/Provider/Cloudflare.py +0 -325
- webscout/Provider/Cohere.py +0 -208
- webscout/Provider/Deepinfra.py +0 -338
- webscout/Provider/ElectronHub.py +0 -773
- webscout/Provider/ExaAI.py +0 -261
- webscout/Provider/ExaChat.py +0 -358
- webscout/Provider/Free2GPT.py +0 -241
- webscout/Provider/GPTWeb.py +0 -249
- webscout/Provider/Gemini.py +0 -169
- webscout/Provider/GithubChat.py +0 -370
- webscout/Provider/GizAI.py +0 -285
- webscout/Provider/Glider.py +0 -222
- webscout/Provider/Groq.py +0 -801
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HeckAI.py +0 -257
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/Jadve.py +0 -291
- webscout/Provider/Koboldai.py +0 -381
- webscout/Provider/LambdaChat.py +0 -411
- webscout/Provider/Llama3.py +0 -259
- webscout/Provider/MCPCore.py +0 -315
- webscout/Provider/Marcus.py +0 -206
- webscout/Provider/Nemotron.py +0 -218
- webscout/Provider/Netwrck.py +0 -270
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/__init__.py +0 -28
- webscout/Provider/OPENAI/ai4chat.py +0 -286
- webscout/Provider/OPENAI/base.py +0 -46
- webscout/Provider/OPENAI/c4ai.py +0 -367
- webscout/Provider/OPENAI/chatgpt.py +0 -549
- webscout/Provider/OPENAI/chatgptclone.py +0 -481
- webscout/Provider/OPENAI/deepinfra.py +0 -309
- webscout/Provider/OPENAI/e2b.py +0 -1350
- webscout/Provider/OPENAI/exaai.py +0 -404
- webscout/Provider/OPENAI/exachat.py +0 -437
- webscout/Provider/OPENAI/freeaichat.py +0 -352
- webscout/Provider/OPENAI/glider.py +0 -316
- webscout/Provider/OPENAI/groq.py +0 -354
- webscout/Provider/OPENAI/heckai.py +0 -341
- webscout/Provider/OPENAI/llmchatco.py +0 -327
- webscout/Provider/OPENAI/mcpcore.py +0 -376
- webscout/Provider/OPENAI/multichat.py +0 -368
- webscout/Provider/OPENAI/netwrck.py +0 -350
- webscout/Provider/OPENAI/opkfc.py +0 -488
- webscout/Provider/OPENAI/scirachat.py +0 -462
- webscout/Provider/OPENAI/sonus.py +0 -294
- webscout/Provider/OPENAI/standardinput.py +0 -425
- webscout/Provider/OPENAI/textpollinations.py +0 -329
- webscout/Provider/OPENAI/toolbaz.py +0 -406
- webscout/Provider/OPENAI/typegpt.py +0 -346
- webscout/Provider/OPENAI/uncovrAI.py +0 -455
- webscout/Provider/OPENAI/utils.py +0 -211
- webscout/Provider/OPENAI/venice.py +0 -413
- webscout/Provider/OPENAI/wisecat.py +0 -381
- webscout/Provider/OPENAI/writecream.py +0 -156
- webscout/Provider/OPENAI/x0gpt.py +0 -371
- webscout/Provider/OPENAI/yep.py +0 -327
- webscout/Provider/OpenGPT.py +0 -209
- webscout/Provider/Openai.py +0 -496
- webscout/Provider/PI.py +0 -429
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/QwenLM.py +0 -254
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -290
- 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/__init__.py +0 -12
- 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/__init__.py +0 -8
- webscout/Provider/TTS/base.py +0 -159
- webscout/Provider/TTS/deepgram.py +0 -156
- webscout/Provider/TTS/elevenlabs.py +0 -111
- webscout/Provider/TTS/gesserit.py +0 -128
- webscout/Provider/TTS/murfai.py +0 -113
- webscout/Provider/TTS/parler.py +0 -111
- webscout/Provider/TTS/speechma.py +0 -180
- webscout/Provider/TTS/streamElements.py +0 -333
- webscout/Provider/TTS/utils.py +0 -280
- webscout/Provider/TeachAnything.py +0 -233
- webscout/Provider/TextPollinationsAI.py +0 -306
- webscout/Provider/TwoAI.py +0 -280
- webscout/Provider/TypliAI.py +0 -305
- webscout/Provider/Venice.py +0 -258
- webscout/Provider/VercelAI.py +0 -253
- webscout/Provider/WiseCat.py +0 -233
- webscout/Provider/WrDoChat.py +0 -370
- webscout/Provider/Writecream.py +0 -237
- webscout/Provider/WritingMate.py +0 -269
- webscout/Provider/Youchat.py +0 -330
- webscout/Provider/__init__.py +0 -178
- webscout/Provider/ai4chat.py +0 -203
- webscout/Provider/aimathgpt.py +0 -189
- webscout/Provider/akashgpt.py +0 -335
- webscout/Provider/asksteve.py +0 -212
- webscout/Provider/bagoodex.py +0 -145
- webscout/Provider/cerebras.py +0 -288
- webscout/Provider/chatglm.py +0 -215
- webscout/Provider/cleeai.py +0 -213
- webscout/Provider/copilot.py +0 -425
- webscout/Provider/elmo.py +0 -283
- webscout/Provider/freeaichat.py +0 -285
- webscout/Provider/geminiapi.py +0 -208
- webscout/Provider/geminiprorealtime.py +0 -160
- webscout/Provider/granite.py +0 -235
- webscout/Provider/hermes.py +0 -266
- webscout/Provider/julius.py +0 -223
- webscout/Provider/koala.py +0 -268
- webscout/Provider/learnfastai.py +0 -325
- webscout/Provider/llama3mitril.py +0 -215
- webscout/Provider/llmchat.py +0 -255
- webscout/Provider/llmchatco.py +0 -306
- webscout/Provider/meta.py +0 -798
- webscout/Provider/multichat.py +0 -364
- webscout/Provider/scira_chat.py +0 -297
- webscout/Provider/scnet.py +0 -243
- webscout/Provider/searchchat.py +0 -292
- webscout/Provider/sonus.py +0 -258
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/toolbaz.py +0 -353
- webscout/Provider/turboseek.py +0 -266
- webscout/Provider/typefully.py +0 -330
- webscout/Provider/typegpt.py +0 -289
- webscout/Provider/uncovr.py +0 -368
- webscout/Provider/x0gpt.py +0 -299
- webscout/Provider/yep.py +0 -389
- webscout/litagent/__init__.py +0 -29
- webscout/litagent/agent.py +0 -455
- webscout/litagent/constants.py +0 -60
- webscout/litprinter/__init__.py +0 -59
- webscout/scout/__init__.py +0 -8
- webscout/scout/core/__init__.py +0 -7
- webscout/scout/core/crawler.py +0 -140
- webscout/scout/core/scout.py +0 -568
- webscout/scout/core/search_result.py +0 -96
- webscout/scout/core/text_analyzer.py +0 -63
- webscout/scout/core/text_utils.py +0 -277
- webscout/scout/core/web_analyzer.py +0 -52
- webscout/scout/core.py +0 -881
- webscout/scout/element.py +0 -460
- webscout/scout/parsers/__init__.py +0 -69
- webscout/scout/parsers/html5lib_parser.py +0 -172
- webscout/scout/parsers/html_parser.py +0 -236
- webscout/scout/parsers/lxml_parser.py +0 -178
- webscout/scout/utils.py +0 -37
- webscout/swiftcli/__init__.py +0 -95
- webscout/swiftcli/core/__init__.py +0 -7
- webscout/swiftcli/core/cli.py +0 -297
- webscout/swiftcli/core/context.py +0 -104
- webscout/swiftcli/core/group.py +0 -241
- webscout/swiftcli/decorators/__init__.py +0 -28
- webscout/swiftcli/decorators/command.py +0 -221
- webscout/swiftcli/decorators/options.py +0 -220
- webscout/swiftcli/decorators/output.py +0 -252
- webscout/swiftcli/exceptions.py +0 -21
- webscout/swiftcli/plugins/__init__.py +0 -9
- webscout/swiftcli/plugins/base.py +0 -135
- webscout/swiftcli/plugins/manager.py +0 -262
- webscout/swiftcli/utils/__init__.py +0 -59
- webscout/swiftcli/utils/formatting.py +0 -252
- webscout/swiftcli/utils/parsing.py +0 -267
- webscout/zeroart/__init__.py +0 -55
- webscout/zeroart/base.py +0 -60
- webscout/zeroart/effects.py +0 -99
- webscout/zeroart/fonts.py +0 -816
- webscout-8.2.6.dist-info/RECORD +0 -307
- webscout-8.2.6.dist-info/entry_points.txt +0 -3
- webscout-8.2.6.dist-info/top_level.txt +0 -2
- 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.6.dist-info → webscout-8.2.7.dist-info}/licenses/LICENSE.md +0 -0
webscout/Extra/weather.py
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Weather information module with a clean, strongly-typed API structure.
|
|
3
|
-
|
|
4
|
-
This module provides a simple client for fetching weather data
|
|
5
|
-
from the wttr.in service with proper typing and a consistent interface.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import requests
|
|
9
|
-
from datetime import datetime
|
|
10
|
-
from typing import List, Dict, Any, Optional
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class CurrentCondition:
|
|
14
|
-
"""Current weather conditions with strongly typed properties."""
|
|
15
|
-
|
|
16
|
-
def __init__(self, data: Dict[str, Any]) -> None:
|
|
17
|
-
"""Initialize with current condition data.
|
|
18
|
-
|
|
19
|
-
Args:
|
|
20
|
-
data: Current condition data dictionary from wttr.in
|
|
21
|
-
"""
|
|
22
|
-
self.temp_c: Optional[str] = data.get('temp_C')
|
|
23
|
-
self.temp_f: Optional[str] = data.get('temp_F')
|
|
24
|
-
self.feels_like_c: Optional[str] = data.get('FeelsLikeC')
|
|
25
|
-
self.feels_like_f: Optional[str] = data.get('FeelsLikeF')
|
|
26
|
-
self.weather_desc: str = data.get('weatherDesc', [{}])[0].get('value', '')
|
|
27
|
-
self.weather_code: Optional[str] = data.get('weatherCode')
|
|
28
|
-
self.humidity: Optional[str] = data.get('humidity')
|
|
29
|
-
self.visibility: Optional[str] = data.get('visibility')
|
|
30
|
-
self.pressure: Optional[str] = data.get('pressure')
|
|
31
|
-
self.wind_speed_kmph: Optional[str] = data.get('windspeedKmph')
|
|
32
|
-
self.wind_direction: Optional[str] = data.get('winddir16Point')
|
|
33
|
-
self.wind_degree: Optional[str] = data.get('winddirDegree')
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class Location:
|
|
37
|
-
"""Location information with strongly typed properties."""
|
|
38
|
-
|
|
39
|
-
def __init__(self, data: Dict[str, Any]) -> None:
|
|
40
|
-
"""Initialize with location data.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
data: Location data dictionary from wttr.in
|
|
44
|
-
"""
|
|
45
|
-
self.name: str = data.get('areaName', [{}])[0].get('value', '')
|
|
46
|
-
self.country: str = data.get('country', [{}])[0].get('value', '')
|
|
47
|
-
self.region: str = data.get('region', [{}])[0].get('value', '')
|
|
48
|
-
self.latitude: Optional[str] = data.get('latitude')
|
|
49
|
-
self.longitude: Optional[str] = data.get('longitude')
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class HourlyForecast:
|
|
53
|
-
"""Hourly forecast information with strongly typed properties."""
|
|
54
|
-
|
|
55
|
-
def __init__(self, data: Dict[str, Any]) -> None:
|
|
56
|
-
"""Initialize with hourly forecast data.
|
|
57
|
-
|
|
58
|
-
Args:
|
|
59
|
-
data: Hourly forecast data dictionary from wttr.in
|
|
60
|
-
"""
|
|
61
|
-
self.time: Optional[str] = data.get('time')
|
|
62
|
-
self.temp_c: Optional[str] = data.get('tempC')
|
|
63
|
-
self.temp_f: Optional[str] = data.get('tempF')
|
|
64
|
-
self.weather_desc: str = data.get('weatherDesc', [{}])[0].get('value', '')
|
|
65
|
-
self.weather_code: Optional[str] = data.get('weatherCode')
|
|
66
|
-
self.wind_speed_kmph: Optional[str] = data.get('windspeedKmph')
|
|
67
|
-
self.wind_direction: Optional[str] = data.get('winddir16Point')
|
|
68
|
-
self.feels_like_c: Optional[str] = data.get('FeelsLikeC')
|
|
69
|
-
self.feels_like_f: Optional[str] = data.get('FeelsLikeF')
|
|
70
|
-
self.chance_of_rain: Optional[str] = data.get('chanceofrain')
|
|
71
|
-
self.chance_of_snow: Optional[str] = data.get('chanceofsnow')
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class DayForecast:
|
|
75
|
-
"""Daily forecast information with strongly typed properties."""
|
|
76
|
-
|
|
77
|
-
def __init__(self, data: Dict[str, Any]) -> None:
|
|
78
|
-
"""Initialize with daily forecast data.
|
|
79
|
-
|
|
80
|
-
Args:
|
|
81
|
-
data: Daily forecast data dictionary from wttr.in
|
|
82
|
-
"""
|
|
83
|
-
self.date: Optional[str] = data.get('date')
|
|
84
|
-
self.date_formatted: Optional[str] = None
|
|
85
|
-
if self.date:
|
|
86
|
-
try:
|
|
87
|
-
self.date_formatted = datetime.strptime(self.date, '%Y-%m-%d').strftime('%a, %b %d')
|
|
88
|
-
except ValueError:
|
|
89
|
-
pass
|
|
90
|
-
|
|
91
|
-
self.max_temp_c: Optional[str] = data.get('maxtempC')
|
|
92
|
-
self.max_temp_f: Optional[str] = data.get('maxtempF')
|
|
93
|
-
self.min_temp_c: Optional[str] = data.get('mintempC')
|
|
94
|
-
self.min_temp_f: Optional[str] = data.get('mintempF')
|
|
95
|
-
self.avg_temp_c: Optional[str] = data.get('avgtempC')
|
|
96
|
-
self.avg_temp_f: Optional[str] = data.get('avgtempF')
|
|
97
|
-
self.sun_hour: Optional[str] = data.get('sunHour')
|
|
98
|
-
|
|
99
|
-
# Parse astronomy data (simplified)
|
|
100
|
-
if data.get('astronomy') and len(data.get('astronomy', [])) > 0:
|
|
101
|
-
astro = data.get('astronomy', [{}])[0]
|
|
102
|
-
self.sunrise: Optional[str] = astro.get('sunrise')
|
|
103
|
-
self.sunset: Optional[str] = astro.get('sunset')
|
|
104
|
-
self.moon_phase: Optional[str] = astro.get('moon_phase')
|
|
105
|
-
else:
|
|
106
|
-
self.sunrise = self.sunset = self.moon_phase = None
|
|
107
|
-
|
|
108
|
-
# Parse hourly forecasts
|
|
109
|
-
self.hourly: List[HourlyForecast] = []
|
|
110
|
-
for hour_data in data.get('hourly', []):
|
|
111
|
-
self.hourly.append(HourlyForecast(hour_data))
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class Weather:
|
|
115
|
-
"""Weather response object with strongly typed properties."""
|
|
116
|
-
|
|
117
|
-
def __init__(self, data: Optional[Dict[str, Any]] = None) -> None:
|
|
118
|
-
"""Initialize with weather data.
|
|
119
|
-
|
|
120
|
-
Args:
|
|
121
|
-
data: Weather data dictionary from wttr.in
|
|
122
|
-
"""
|
|
123
|
-
if not data:
|
|
124
|
-
self.current_condition = None
|
|
125
|
-
self.location = None
|
|
126
|
-
self.forecast_days = []
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
# Parse current condition
|
|
130
|
-
self.current_condition: Optional[CurrentCondition] = None
|
|
131
|
-
if data.get('current_condition') and len(data.get('current_condition', [])) > 0:
|
|
132
|
-
self.current_condition = CurrentCondition(data.get('current_condition', [{}])[0])
|
|
133
|
-
|
|
134
|
-
# Parse location
|
|
135
|
-
self.location: Optional[Location] = None
|
|
136
|
-
if data.get('nearest_area') and len(data.get('nearest_area', [])) > 0:
|
|
137
|
-
self.location = Location(data.get('nearest_area', [{}])[0])
|
|
138
|
-
|
|
139
|
-
# Parse forecast days
|
|
140
|
-
self.forecast_days: List[DayForecast] = []
|
|
141
|
-
for day_data in data.get('weather', []):
|
|
142
|
-
self.forecast_days.append(DayForecast(day_data))
|
|
143
|
-
|
|
144
|
-
@property
|
|
145
|
-
def today(self) -> Optional[DayForecast]:
|
|
146
|
-
"""Get today's forecast."""
|
|
147
|
-
return self.forecast_days[0] if self.forecast_days else None
|
|
148
|
-
|
|
149
|
-
@property
|
|
150
|
-
def tomorrow(self) -> Optional[DayForecast]:
|
|
151
|
-
"""Get tomorrow's forecast."""
|
|
152
|
-
return self.forecast_days[1] if len(self.forecast_days) > 1 else None
|
|
153
|
-
|
|
154
|
-
@property
|
|
155
|
-
def summary(self) -> str:
|
|
156
|
-
"""Get a simple text summary of current weather."""
|
|
157
|
-
if not self.current_condition or not self.location:
|
|
158
|
-
return "Weather data not available"
|
|
159
|
-
|
|
160
|
-
return f"{self.location.name}, {self.location.country}: {self.current_condition.weather_desc}, {self.current_condition.temp_c}°C ({self.current_condition.temp_f}°F)"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
class WeatherClient:
|
|
164
|
-
"""Client for fetching weather information."""
|
|
165
|
-
|
|
166
|
-
def get_weather(self, location: str) -> Weather:
|
|
167
|
-
"""Get weather for the specified location.
|
|
168
|
-
|
|
169
|
-
Args:
|
|
170
|
-
location: Location to get weather for (city name, zip code, etc.)
|
|
171
|
-
|
|
172
|
-
Returns:
|
|
173
|
-
Weather object containing all weather data
|
|
174
|
-
"""
|
|
175
|
-
try:
|
|
176
|
-
response = requests.get(f"https://wttr.in/{location}?format=j1", timeout=10)
|
|
177
|
-
response.raise_for_status()
|
|
178
|
-
return Weather(response.json())
|
|
179
|
-
except Exception as e:
|
|
180
|
-
print(f"Error fetching weather data: {str(e)}")
|
|
181
|
-
return Weather()
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def get(location: str) -> Weather:
|
|
185
|
-
"""Convenience function to get weather for a location.
|
|
186
|
-
|
|
187
|
-
Args:
|
|
188
|
-
location: Location to get weather for
|
|
189
|
-
|
|
190
|
-
Returns:
|
|
191
|
-
Weather object containing all weather data
|
|
192
|
-
"""
|
|
193
|
-
client = WeatherClient()
|
|
194
|
-
return client.get_weather(location)
|
webscout/Extra/weather_ascii.py
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Weather ASCII art visualization module with a simple, strongly-typed API.
|
|
3
|
-
|
|
4
|
-
This module provides a clean interface for fetching weather information
|
|
5
|
-
in ASCII art format using the wttr.in service.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import requests
|
|
9
|
-
from typing import Dict, Optional, Any
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class WeatherAscii:
|
|
13
|
-
"""Container for ASCII weather data with a simple API."""
|
|
14
|
-
|
|
15
|
-
def __init__(self, content: str) -> None:
|
|
16
|
-
"""Initialize with ASCII weather content.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
content: ASCII weather data or error message
|
|
20
|
-
"""
|
|
21
|
-
self._content = content
|
|
22
|
-
|
|
23
|
-
@property
|
|
24
|
-
def content(self) -> str:
|
|
25
|
-
"""Get the ASCII content, similar to choices.message.content in OpenAI API."""
|
|
26
|
-
return self._content
|
|
27
|
-
|
|
28
|
-
def __str__(self) -> str:
|
|
29
|
-
"""String representation of ASCII weather."""
|
|
30
|
-
return self.content
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class WeatherAsciiClient:
|
|
34
|
-
"""Client for fetching weather information in ASCII art."""
|
|
35
|
-
|
|
36
|
-
def get_weather(self, location: str, params: Optional[Dict[str, Any]] = None) -> WeatherAscii:
|
|
37
|
-
"""Get ASCII weather for a location.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
location: The location for which to fetch weather data
|
|
41
|
-
params: Additional parameters for the request
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
WeatherAscii object containing ASCII art weather data
|
|
45
|
-
"""
|
|
46
|
-
url = f"https://wttr.in/{location}"
|
|
47
|
-
headers = {'User-Agent': 'curl'}
|
|
48
|
-
|
|
49
|
-
try:
|
|
50
|
-
response = requests.get(url, headers=headers, params=params, timeout=10)
|
|
51
|
-
response.raise_for_status()
|
|
52
|
-
|
|
53
|
-
if response.status_code == 200:
|
|
54
|
-
# Remove the footer line from wttr.in
|
|
55
|
-
ascii_weather = "\n".join(response.text.splitlines()[:-1])
|
|
56
|
-
return WeatherAscii(ascii_weather)
|
|
57
|
-
else:
|
|
58
|
-
error_msg = f"Error: Unable to fetch weather data. Status code: {response.status_code}"
|
|
59
|
-
return WeatherAscii(error_msg)
|
|
60
|
-
except requests.exceptions.RequestException as e:
|
|
61
|
-
return WeatherAscii(f"Error: {str(e)}")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def get(location: str, params: Optional[Dict[str, Any]] = None) -> WeatherAscii:
|
|
65
|
-
"""Convenience function to get ASCII weather for a location.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
location: Location to get weather for
|
|
69
|
-
params: Additional parameters for the request
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
WeatherAscii object containing ASCII art weather data
|
|
73
|
-
"""
|
|
74
|
-
client = WeatherAsciiClient()
|
|
75
|
-
return client.get_weather(location, params)
|
|
76
|
-
|
webscout/Litlogger/__init__.py
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
LitLogger - A feature-rich, colorful logging library with intelligent level detection.
|
|
3
|
-
|
|
4
|
-
Features:
|
|
5
|
-
- Colorful console output
|
|
6
|
-
- Multiple output formats including JSON
|
|
7
|
-
- File logging with rotation
|
|
8
|
-
- Network logging (HTTP/HTTPS/TCP)
|
|
9
|
-
- Async logging support
|
|
10
|
-
- Intelligent log level detection
|
|
11
|
-
- Context managers
|
|
12
|
-
- Performance metrics
|
|
13
|
-
- Log aggregation
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
from .core.logger import Logger
|
|
17
|
-
from .core.level import LogLevel
|
|
18
|
-
from .styles.colors import LogColors
|
|
19
|
-
from .styles.formats import LogFormat
|
|
20
|
-
from .styles.text import TextStyle
|
|
21
|
-
from .handlers.console import ConsoleHandler, ErrorConsoleHandler
|
|
22
|
-
from .handlers.file import FileHandler
|
|
23
|
-
from .handlers.network import NetworkHandler
|
|
24
|
-
from .utils.detectors import LevelDetector
|
|
25
|
-
from .utils.formatters import MessageFormatter
|
|
26
|
-
|
|
27
|
-
# Create a default logger instance
|
|
28
|
-
default_logger = Logger(
|
|
29
|
-
name="LitLogger",
|
|
30
|
-
handlers=[ConsoleHandler()]
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
# Expose common logging methods at package level
|
|
34
|
-
debug = default_logger.debug
|
|
35
|
-
info = default_logger.info
|
|
36
|
-
warning = default_logger.warning
|
|
37
|
-
error = default_logger.error
|
|
38
|
-
critical = default_logger.critical
|
|
39
|
-
|
|
40
|
-
__all__ = [
|
|
41
|
-
# Core
|
|
42
|
-
"Logger",
|
|
43
|
-
"LogLevel",
|
|
44
|
-
|
|
45
|
-
# Styles
|
|
46
|
-
"LogColors",
|
|
47
|
-
"LogFormat",
|
|
48
|
-
"TextStyle",
|
|
49
|
-
|
|
50
|
-
# Handlers
|
|
51
|
-
"ConsoleHandler",
|
|
52
|
-
"ErrorConsoleHandler",
|
|
53
|
-
"FileHandler",
|
|
54
|
-
"NetworkHandler",
|
|
55
|
-
|
|
56
|
-
# Utils
|
|
57
|
-
"LevelDetector",
|
|
58
|
-
"MessageFormatter",
|
|
59
|
-
|
|
60
|
-
# Package-level logging functions
|
|
61
|
-
"debug",
|
|
62
|
-
"info",
|
|
63
|
-
"warning",
|
|
64
|
-
"error",
|
|
65
|
-
"critical",
|
|
66
|
-
|
|
67
|
-
]
|
webscout/Litlogger/core/level.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
|
|
3
|
-
class LogLevel(Enum):
|
|
4
|
-
NOTSET = 0
|
|
5
|
-
DEBUG = 10
|
|
6
|
-
INFO = 20
|
|
7
|
-
WARNING = 30
|
|
8
|
-
ERROR = 40
|
|
9
|
-
CRITICAL = 50
|
|
10
|
-
|
|
11
|
-
@staticmethod
|
|
12
|
-
def get_level(level_str: str) -> 'LogLevel':
|
|
13
|
-
if not level_str:
|
|
14
|
-
return LogLevel.NOTSET
|
|
15
|
-
try:
|
|
16
|
-
return LogLevel[level_str.upper()]
|
|
17
|
-
except KeyError:
|
|
18
|
-
raise ValueError(f"Invalid log level: {level_str}")
|
|
19
|
-
|
|
20
|
-
def __lt__(self, other):
|
|
21
|
-
if isinstance(other, LogLevel):
|
|
22
|
-
return self.value < other.value
|
|
23
|
-
return NotImplemented
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import asyncio
|
|
3
|
-
import sys
|
|
4
|
-
import threading
|
|
5
|
-
import traceback
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from typing import List, Union
|
|
8
|
-
|
|
9
|
-
from ..core.level import LogLevel
|
|
10
|
-
from ..styles.formats import LogFormat
|
|
11
|
-
|
|
12
|
-
class Logger:
|
|
13
|
-
# Emoji mappings for different log levels
|
|
14
|
-
LEVEL_EMOJIS = {
|
|
15
|
-
LogLevel.DEBUG: "🔍",
|
|
16
|
-
LogLevel.INFO: "ℹ️",
|
|
17
|
-
LogLevel.WARNING: "⚠️",
|
|
18
|
-
LogLevel.ERROR: "❌",
|
|
19
|
-
LogLevel.CRITICAL: "🔥"
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
name: str = "LitLogger",
|
|
25
|
-
level: Union[str, LogLevel, None] = None,
|
|
26
|
-
format: Union[str, LogFormat] = LogFormat.MODERN_EMOJI,
|
|
27
|
-
handlers: List = None,
|
|
28
|
-
enable_colors: bool = True,
|
|
29
|
-
async_mode: bool = False,
|
|
30
|
-
show_thread: bool = True,
|
|
31
|
-
show_context: bool = True
|
|
32
|
-
):
|
|
33
|
-
self.name = name
|
|
34
|
-
self.level = LogLevel.NOTSET if level is None else (
|
|
35
|
-
LogLevel.get_level(level) if isinstance(level, str) else level
|
|
36
|
-
)
|
|
37
|
-
self.format = format
|
|
38
|
-
self.enable_colors = enable_colors
|
|
39
|
-
self.async_mode = async_mode
|
|
40
|
-
self.show_thread = show_thread
|
|
41
|
-
self.show_context = show_context
|
|
42
|
-
self._context_data = {}
|
|
43
|
-
|
|
44
|
-
# Initialize with default console handler if none provided
|
|
45
|
-
if handlers is None:
|
|
46
|
-
from ..handlers.console import ConsoleHandler
|
|
47
|
-
self.handlers = [ConsoleHandler(level=self.level)]
|
|
48
|
-
else:
|
|
49
|
-
self.handlers = handlers
|
|
50
|
-
|
|
51
|
-
def _format_message(self, level: LogLevel, message: str, **kwargs) -> str:
|
|
52
|
-
now = datetime.now()
|
|
53
|
-
emoji = self.LEVEL_EMOJIS.get(level, "") if self.enable_colors else ""
|
|
54
|
-
|
|
55
|
-
log_data = {
|
|
56
|
-
"timestamp": now.strftime("%H:%M:%S"),
|
|
57
|
-
"level": level.name,
|
|
58
|
-
"name": self.name,
|
|
59
|
-
"message": str(message),
|
|
60
|
-
"emoji": emoji,
|
|
61
|
-
"thread": threading.current_thread().name if self.show_thread else "",
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
# Add context data
|
|
65
|
-
if self.show_context and self._context_data:
|
|
66
|
-
log_data.update(self._context_data)
|
|
67
|
-
|
|
68
|
-
# Add extra kwargs
|
|
69
|
-
log_data.update(kwargs)
|
|
70
|
-
|
|
71
|
-
# Format exception if present
|
|
72
|
-
if 'exc_info' in kwargs:
|
|
73
|
-
exc_info = kwargs['exc_info']
|
|
74
|
-
if exc_info:
|
|
75
|
-
exception_text = ''.join(traceback.format_exception(*exc_info))
|
|
76
|
-
log_data['message'] = f"{message}\n{exception_text}"
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
base_message = f"{emoji} [{log_data['timestamp']}] {level.name} {log_data['message']}"
|
|
80
|
-
return base_message
|
|
81
|
-
except Exception as e:
|
|
82
|
-
return f"[{log_data['timestamp']}] {level.name}: {message}"
|
|
83
|
-
|
|
84
|
-
def _log(self, level: LogLevel, message: str, **kwargs):
|
|
85
|
-
if self.async_mode:
|
|
86
|
-
loop = asyncio.get_event_loop()
|
|
87
|
-
if loop.is_running():
|
|
88
|
-
return asyncio.create_task(self._async_log(level, message, **kwargs))
|
|
89
|
-
else:
|
|
90
|
-
return loop.run_until_complete(self._async_log(level, message, **kwargs))
|
|
91
|
-
return self._sync_log(level, message, **kwargs)
|
|
92
|
-
|
|
93
|
-
def debug(self, message: str, **kwargs):
|
|
94
|
-
self._log(LogLevel.DEBUG, message, **kwargs)
|
|
95
|
-
|
|
96
|
-
def info(self, message: str, **kwargs):
|
|
97
|
-
self._log(LogLevel.INFO, message, **kwargs)
|
|
98
|
-
|
|
99
|
-
def warning(self, message: str, **kwargs):
|
|
100
|
-
self._log(LogLevel.WARNING, message, **kwargs)
|
|
101
|
-
|
|
102
|
-
def error(self, message: str, **kwargs):
|
|
103
|
-
self._log(LogLevel.ERROR, message, **kwargs)
|
|
104
|
-
|
|
105
|
-
def critical(self, message: str, **kwargs):
|
|
106
|
-
self._log(LogLevel.CRITICAL, message, **kwargs)
|
|
107
|
-
|
|
108
|
-
def exception(self, message: str, exc_info=True, **kwargs):
|
|
109
|
-
"""
|
|
110
|
-
Log an exception with traceback.
|
|
111
|
-
|
|
112
|
-
Args:
|
|
113
|
-
message: The message to log
|
|
114
|
-
exc_info: If True, adds exception info to the message. Can also be a tuple (type, value, traceback)
|
|
115
|
-
**kwargs: Additional key-value pairs to log
|
|
116
|
-
"""
|
|
117
|
-
if exc_info:
|
|
118
|
-
if not isinstance(exc_info, tuple):
|
|
119
|
-
exc_info = sys.exc_info()
|
|
120
|
-
kwargs['exc_info'] = exc_info
|
|
121
|
-
self.error(message, **kwargs)
|
|
122
|
-
|
|
123
|
-
def _sync_log(self, level: LogLevel, message: str, **kwargs):
|
|
124
|
-
if self._should_log(level):
|
|
125
|
-
formatted_message = self._format_message(level, message, **kwargs)
|
|
126
|
-
for handler in self.handlers:
|
|
127
|
-
if handler.level == LogLevel.NOTSET or level.value >= handler.level.value:
|
|
128
|
-
handler.emit(formatted_message, level)
|
|
129
|
-
|
|
130
|
-
async def _async_log(self, level: LogLevel, message: str, **kwargs):
|
|
131
|
-
if self._should_log(level):
|
|
132
|
-
formatted_message = self._format_message(level, message, **kwargs)
|
|
133
|
-
tasks = []
|
|
134
|
-
for handler in self.handlers:
|
|
135
|
-
if handler.level == LogLevel.NOTSET or level.value >= handler.level.value:
|
|
136
|
-
if hasattr(handler, 'async_emit'):
|
|
137
|
-
tasks.append(handler.async_emit(formatted_message, level))
|
|
138
|
-
else:
|
|
139
|
-
tasks.append(asyncio.to_thread(handler.emit, formatted_message, level))
|
|
140
|
-
await asyncio.gather(*tasks)
|
|
141
|
-
|
|
142
|
-
def _should_log(self, level: LogLevel) -> bool:
|
|
143
|
-
return self.level == LogLevel.NOTSET or level.value >= self.level.value
|
|
144
|
-
|
|
145
|
-
def set_context(self, **kwargs):
|
|
146
|
-
self._context_data.update(kwargs)
|
|
147
|
-
|
|
148
|
-
def clear_context(self):
|
|
149
|
-
self._context_data.clear()
|
|
150
|
-
|
|
151
|
-
def set_style(self, style: str):
|
|
152
|
-
"""Set logger style format."""
|
|
153
|
-
if style in LogFormat.TEMPLATES:
|
|
154
|
-
self.format = LogFormat.TEMPLATES[style]
|
|
155
|
-
else:
|
|
156
|
-
raise ValueError(f"Unknown style: {style}")
|
|
157
|
-
|
|
158
|
-
def __enter__(self):
|
|
159
|
-
return self
|
|
160
|
-
|
|
161
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
162
|
-
if exc_type is not None:
|
|
163
|
-
self.error(f"Context exited with error: {exc_val}")
|
|
164
|
-
return False
|
|
165
|
-
return True
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"""Log output handlers for different destinations."""
|
|
2
|
-
|
|
3
|
-
from .console import ConsoleHandler, ErrorConsoleHandler
|
|
4
|
-
from .file import FileHandler
|
|
5
|
-
from .network import NetworkHandler
|
|
6
|
-
|
|
7
|
-
__all__ = [
|
|
8
|
-
"ConsoleHandler",
|
|
9
|
-
"ErrorConsoleHandler",
|
|
10
|
-
"FileHandler",
|
|
11
|
-
"NetworkHandler"
|
|
12
|
-
]
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from ..core.level import LogLevel
|
|
3
|
-
from ..styles.colors import LogColors
|
|
4
|
-
|
|
5
|
-
class ConsoleHandler:
|
|
6
|
-
def __init__(self, level: LogLevel = LogLevel.DEBUG, stream=sys.stdout):
|
|
7
|
-
self.level = level
|
|
8
|
-
self.stream = stream
|
|
9
|
-
self.colors = LogColors()
|
|
10
|
-
|
|
11
|
-
def emit(self, message: str, level: LogLevel):
|
|
12
|
-
"""Write the colored message to the console."""
|
|
13
|
-
try:
|
|
14
|
-
# Apply color based on log level
|
|
15
|
-
color = LogColors.LEVEL_COLORS.get(level, LogColors.RESET)
|
|
16
|
-
colored_message = f"{color}{message}{LogColors.RESET}"
|
|
17
|
-
print(colored_message, file=self.stream, flush=True)
|
|
18
|
-
except Exception as e:
|
|
19
|
-
# Fallback to plain printing if coloring fails
|
|
20
|
-
print(message, file=self.stream, flush=True)
|
|
21
|
-
|
|
22
|
-
async def async_emit(self, message: str, level: LogLevel):
|
|
23
|
-
"""
|
|
24
|
-
Asynchronously write log message to console.
|
|
25
|
-
Just calls emit() since console output is generally fast enough.
|
|
26
|
-
"""
|
|
27
|
-
self.emit(message, level)
|
|
28
|
-
|
|
29
|
-
class ErrorConsoleHandler(ConsoleHandler):
|
|
30
|
-
"""Specialized handler that writes to stderr."""
|
|
31
|
-
|
|
32
|
-
def __init__(self, level: LogLevel = LogLevel.ERROR):
|
|
33
|
-
super().__init__(stream=sys.stderr, level=level)
|