Skill: yuboon/weather-skill-0311 (version 1.0.0)

--- name: weather-query version: 1.0.0 description: 查询全球任意城市天气，支持中文城市名 author: AIStudio homepage: https://example.com/weather-query-skill --- # Weather Query Skill 基于 wttr.in 的天气查询技能，支持离线测试模式。 ## 功能 - 查询指定城市天气 - 支持中文城市名 - 返回温度、湿度、天气状况 - 支持 `--offline` 演示模式，便于无网验证 ## 使用 ```powershell python scripts/weather.py 北京 python scripts/weather.py 北京 --offline ``` ## 安装 ```bash clawhub install your-name/weather-query ```

path: scripts/weather.py
content: #!/usr/bin/env python3
"""Weather Query Skill - wttr.in based example with offline mode."""
from __future__ import annotations

import json
import sys
import urllib.parse
import urllib.request
from typing import Any

OFFLINE_SAMPLE = {
    'current_condition': [
        {
            'temp_C': '15',
            'temp_F': '59',
            'humidity': '45',
            'weatherDesc': [{'value': '晴朗'}],
            'windspeedKmph': '12',
            'observation_time': '09:00',
        }
    ]
}


def parse_weather_payload(city: str, data: dict[str, Any]) -> dict[str, str]:
    current = data['current_condition'][0]
    return {
        'city': city,
        'temp_c': current['temp_C'],
        'temp_f': current['temp_F'],
        'humidity': current['humidity'],
        'weather': current['weatherDesc'][0]['value'],
        'wind': f"{current['windspeedKmph']} km/h",
        'observed': current['observation_time'],
    }


def get_weather(city: str, *, offline: bool = False, timeout: int = 10) -> dict[str, str]:
    try:
        if offline:
            return parse_weather_payload(city, OFFLINE_SAMPLE)

        encoded_city = urllib.parse.quote(city)
        url = f'http://wttr.in/{encoded_city}?format=j1'
        req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})

        with urllib.request.urlopen(req, timeout=timeout) as response:
            data = json.loads(response.read().decode('utf-8'))
        return parse_weather_payload(city, data)
    except Exception as exc:
        return {'error': str(exc)}


def main(argv: list[str] | None = None) -> int:
    args = argv if argv is not None else sys.argv[1:]
    if not args:
        print(json.dumps({'error': '请提供城市名，如：python weather.py 北京'}, ensure_ascii=False))
        return 1

    city = args[0]
    offline = '--offline' in args[1:]
    print(json.dumps(get_weather(city, offline=offline), ensure_ascii=False, indent=2))
    return 0


if __name__ == '__main__':
    raise SystemExit(main())


path: tests/test_weather.py
content: import io
import json
import subprocess
import sys
import unittest
from pathlib import Path
from unittest import mock

SCRIPT = Path(__file__).resolve().parents[1] / 'scripts' / 'weather.py'
sys.path.insert(0, str(SCRIPT.parent))

import weather  # noqa: E402


class WeatherSkillTests(unittest.TestCase):
    def test_offline_mode_returns_sample_payload(self) -> None:
        result = weather.get_weather('北京', offline=True)
        self.assertEqual(result['city'], '北京')
        self.assertEqual(result['weather'], '晴朗')
        self.assertEqual(result['temp_c'], '15')

    def test_online_mode_parses_http_response(self) -> None:
        payload = {
            'current_condition': [
                {
                    'temp_C': '22',
                    'temp_F': '71',
                    'humidity': '30',
                    'weatherDesc': [{'value': 'Partly cloudy'}],
                    'windspeedKmph': '8',
                    'observation_time': '06:30 PM',
                }
            ]
        }

        class FakeResponse(io.BytesIO):
            def __enter__(self):
                return self

            def __exit__(self, exc_type, exc, tb):
                self.close()
                return False

        with mock.patch('weather.urllib.request.urlopen', return_value=FakeResponse(json.dumps(payload).encode('utf-8'))):
            result = weather.get_weather('Tokyo')

        self.assertEqual(result['city'], 'Tokyo')
        self.assertEqual(result['weather'], 'Partly cloudy')
        self.assertEqual(result['wind'], '8 km/h')

    def test_cli_offline_outputs_json(self) -> None:
        completed = subprocess.run(
            [sys.executable, str(SCRIPT), '北京', '--offline'],
            check=True,
            capture_output=True,
            text=True,
        )
        payload = json.loads(completed.stdout)
        self.assertEqual(payload['city'], '北京')
        self.assertIn('temp_c', payload)


if __name__ == '__main__':
    unittest.main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)