isobar-cli 1.1.2__tar.gz → 1.3.0__tar.gz

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 (26) hide show
  1. {isobar_cli-1.1.2/src/isobar_cli.egg-info → isobar_cli-1.3.0}/PKG-INFO +114 -39
  2. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/README.md +110 -37
  3. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/pyproject.toml +13 -10
  4. isobar_cli-1.3.0/src/isobar_cli/__init__.py +1 -0
  5. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli/api.py +42 -10
  6. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli/config.py +21 -0
  7. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli/logic.py +72 -2
  8. isobar_cli-1.3.0/src/isobar_cli/ui.py +582 -0
  9. {isobar_cli-1.1.2 → isobar_cli-1.3.0/src/isobar_cli.egg-info}/PKG-INFO +114 -39
  10. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli.egg-info/requires.txt +3 -0
  11. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/tests/test_ui.py +9 -6
  12. isobar_cli-1.1.2/src/isobar_cli/__init__.py +0 -1
  13. isobar_cli-1.1.2/src/isobar_cli/ui.py +0 -259
  14. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/LICENSE +0 -0
  15. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/setup.cfg +0 -0
  16. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli/location.py +0 -0
  17. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli/main.py +0 -0
  18. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli/models.py +0 -0
  19. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli.egg-info/SOURCES.txt +0 -0
  20. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli.egg-info/dependency_links.txt +0 -0
  21. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli.egg-info/entry_points.txt +0 -0
  22. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/src/isobar_cli.egg-info/top_level.txt +0 -0
  23. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/tests/test_api.py +0 -0
  24. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/tests/test_isobar_extra.py +0 -0
  25. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/tests/test_location.py +0 -0
  26. {isobar_cli-1.1.2 → isobar_cli-1.3.0}/tests/test_main.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isobar-cli
3
- Version: 1.1.2
4
- Summary: A visually pleasing terminal weather tool focusing on Real Feel and Windchill.
3
+ Version: 1.3.0
4
+ Summary: A terminal weather tool with industrial aesthetic, focusing on Real Feel and Windchill.
5
5
  Author: Beau Bremer / KnowOneActual
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/KnowOneActual/isobar-cli
@@ -29,6 +29,8 @@ Provides-Extra: test
29
29
  Requires-Dist: pytest>=7.0.0; extra == "test"
30
30
  Requires-Dist: requests-mock>=1.11.0; extra == "test"
31
31
  Requires-Dist: pytest-cov>=4.1.0; extra == "test"
32
+ Provides-Extra: timezone
33
+ Requires-Dist: pytz>=2024.1; extra == "timezone"
32
34
  Dynamic: license-file
33
35
 
34
36
  # Isobar CLI
@@ -36,7 +38,7 @@ Dynamic: license-file
36
38
  ![CI](https://github.com/KnowOneActual/isobar-cli/actions/workflows/ci.yml/badge.svg)
37
39
  ![Coverage](https://img.shields.io/badge/coverage-98%25-green)
38
40
  [![PyPI version](https://badge.fury.io/py/isobar-cli.svg)](https://badge.fury.io/py/isobar-cli)
39
- ![Version](https://img.shields.io/badge/version-1.0.1-blue)
41
+ ![Version](https://img.shields.io/badge/version-1.3.0-blue)
40
42
  ![Ruff](https://img.shields.io/badge/linting-ruff-purple)
41
43
  ![Python](https://img.shields.io/badge/python-3.8%2B-blue)
42
44
  ![License](https://img.shields.io/badge/license-MIT-green)
@@ -54,11 +56,13 @@ Most weather apps overwhelm with data. Isobar strips away everything except what
54
56
  - **Essential over comprehensive** — Show Real Feel, not 47 data points.
55
57
  - **Terminal-native** — Built for quick checks within a developer workflow.
56
58
  - **Zero friction** — No API keys or configuration files required.
57
- - **Information density** — Clean, borderless UI for maximum readability.
59
+ - **Information density** — Industrial dashboard UI for maximum readability.
58
60
  - **Intentional features** — Each feature must answer: *"Does this help someone understand what it feels like outside?"*
61
+ - **Distinctive aesthetic** — Retro-futuristic industrial styling that avoids generic "AI slop"
59
62
 
60
63
  ## ✨ Features
61
64
 
65
+ - **Industrial Aesthetic** — Retro-futuristic weather observatory dashboard with brutalist styling 🏭
62
66
  - **Auto-Location** — `isobar` detects the city automatically 🌍
63
67
  - **Weather Condition Icons** — WMO-standard emoji + plain-English description (☀️ Clear sky, 🌨️ Moderate snow, ⛈️ Thunderstorm)
64
68
  - **Real Feel** — Apparent temperature metrics (what it *actually* feels like).
@@ -75,12 +79,16 @@ Most weather apps overwhelm with data. Isobar strips away everything except what
75
79
  - **Metric Support** — `--metric` or `-m` for Celsius, km/h, and mm.
76
80
  - **No API Keys** — Free Open-Meteo and ip-api.com.
77
81
  - **Zero Config** — Works instantly after installation.
82
+ - **Visual Gauges** — Temperature and humidity gauge visualizations 📊
83
+ - **Severity Indicators** — Weather condition severity icons (⚡, ▲, ●, ○, ◇)
84
+ - **Wind Categories** — Descriptive wind speed classifications (CALM, LIGHT, GENTLE, etc.)
85
+ - **Industrial Styling** — Heavy borders, uppercase labels, status columns
78
86
  - **Phase 7: Intuition & Analysis** — Higher-level context and automated insights:
79
- - **Preparation Guidance** — Clothing and gear suggestions based on conditions 🧥☂️🧴
87
+ - **Preparation Guidance** — Clothing and gear suggestions with priority levels 🧥☂️🧴
80
88
  - **Temporal Context** — Comparison with previous day conditions 📈
81
89
  - **UV Index Monitoring** — Sun protection guidance with intensity levels ☀️
82
90
  - **Wind Gust Alerts** — Highlighting of significant gust events 💨⚠️
83
- - **Home City Persistence** — Set a default city with `isobar home "Your City"` 🏠
91
+ - **Home City Persistence** — Set a default city with `isobar home "Your City"` 🏠 *(Note: Due to a Typer limitation, this currently shows weather for "Home, Kansas" instead of setting home city. Manual config editing required.)*
84
92
 
85
93
  ## 🚀 Installation
86
94
 
@@ -124,12 +132,16 @@ isobar London Tokyo Paris # Multiple cities
124
132
  isobar "New York" # Use quotes for multi-word cities
125
133
 
126
134
  # Hourly outlook (next 12h)
127
- isobar --hourly
128
- isobar -H
135
+ isobar --hourly Chicago
136
+ isobar -H Chicago
129
137
 
130
138
  # 7-day forecast
131
- isobar --forecast
132
- isobar -f
139
+ isobar --forecast Chicago
140
+ isobar -f Chicago
141
+
142
+ # Note: Flags must come before city names
143
+ # ✅ isobar -H Chicago
144
+ # ❌ isobar Chicago -H (treats "-H" as a city name)
133
145
  isobar "San Francisco" --forecast
134
146
  isobar -f Sydney
135
147
 
@@ -145,6 +157,42 @@ isobar home --clear # Clear home city
145
157
  isobar # Uses home city if set (otherwise auto-detects)
146
158
  ```
147
159
 
160
+ ## ⚙️ Configuration
161
+
162
+ Isobar supports configuration via environment variables for advanced use cases:
163
+
164
+ ### API Endpoint Configuration
165
+ Customize API endpoints for different weather providers or testing:
166
+
167
+ ```bash
168
+ # Use custom weather APIs
169
+ export ISOBAR_GEOCODING_URL="https://custom-geocoding-api.example.com/v1/search"
170
+ export ISOBAR_WEATHER_URL="https://custom-weather-api.example.com/v1/forecast"
171
+ export ISOBAR_AQI_URL="https://custom-aqi-api.example.com/v1/air-quality"
172
+
173
+ # Run with custom endpoints
174
+ isobar "New York"
175
+ ```
176
+
177
+ ### Timezone Support
178
+ For enhanced timezone accuracy (optional):
179
+
180
+ ```bash
181
+ # Install optional timezone support
182
+ pip install isobar-cli[timezone]
183
+
184
+ # Sunrise/sunset will now display in local timezone
185
+ isobar London
186
+ ```
187
+
188
+ ### Debug Mode
189
+ Enable debug logging to stderr:
190
+
191
+ ```bash
192
+ # View API errors and debugging information
193
+ isobar "Test City" 2> debug.log
194
+ ```
195
+
148
196
  ## ⌨️ Shell Completion
149
197
 
150
198
  Isobar supports tab-completion for city names. To enable it for a shell:
@@ -163,36 +211,53 @@ isobar --install-completion bash
163
211
 
164
212
  ## 🖥️ Example Output
165
213
 
214
+ ### Industrial Aesthetic (v1.3.0+)
215
+
216
+ ```
217
+ ┌─ WEATHER OBSERVATORY ─┐
218
+ CHICAGO
219
+ ┌─────┬──────────────────────┬────────────────┬────────────────┐
220
+ │ │ METRIC │ READING │ STATUS │
221
+ ├─────┼──────────────────────┼────────────────┼────────────────┤
222
+ │ ☀️ │ CONDITIONS │ MAINLY CLEAR │ ◇ │
223
+ │ 🌡️ │ TEMPERATURE │ 75.2°F │ [███░░░░░░░] │
224
+ │ 🤔 │ REAL FEEL │ 78.5°F │ ▲ 3.3°F │
225
+ │ 💨 │ WIND SPEED │ 12.4 mph │ GENTLE │
226
+ │ 💧 │ HUMIDITY │ 65% │ [▓▓▓░░] │
227
+ │ 😷 │ AIR QUALITY │ 45 │ GOOD ◇ │
228
+ │ ☔ │ PRECIPITATION │ 30% (6h) │ [▓░░] │
229
+ │ │ FORECAST │ LIGHT RAIN LIKELY │ │
230
+ │ 🌅 │ SUNRISE │ 06:29 │ DAWN │
231
+ │ 🌇 │ SUNSET │ 17:37 │ DUSK │
232
+ │ ☀️ │ UV INDEX │ 6.5 │ HIGH ☀️☀️☀️ │
233
+ │ ⚡ │ GUST ALERT │ 25 mph │ ⚠️ SEVERE │
234
+ └─────┴──────────────────────┴────────────────┴────────────────┘
235
+
236
+ ┌─ TREND ANALYSIS ─┐
237
+ ↑ 5.2°F WARMER THAN YESTERDAY
238
+ └──────────────────┘
239
+
240
+ ┌─ PREPARATION PROTOCOL ─┐
241
+ ⚠️ HIGH PRIORITY
242
+ ▶ Wind gusts up to 25 mph - secure loose items
243
+ ▲ RECOMMENDED
244
+ ▶ Light jacket recommended
245
+ ▶ Sunscreen recommended (UV: High)
246
+ ○ ADVISORY
247
+ ▶ Sunglasses recommended for glare
248
+ └─────────────────────────┘
249
+
250
+ ┌─ FORECAST PANEL ─┐
251
+ CHICAGO
252
+ ┌──────┬──┬────────────────────┬───────┬───────┬───────┬────────┐
253
+ │ DAY │ │ CONDITIONS │ HIGH │ LOW │ RAIN% │ STATUS │
254
+ ├──────┼──┼────────────────────┼───────┼───────┼───────┼────────┤
255
+ │ TODAY│☀️│ MAINLY CLEAR │ 78.7°F│ 63.9°F│ 30% │ ○ │
256
+ │ TUE │⛅│ PARTLY CLOUDY │ 82.4°F│ 65.4°F│ 20% │ ○ │
257
+ │ WED │🌦️│ LIGHT DRIZZLE │ 76.8°F│ 60.9°F│ 45% │ ● │
258
+ │ THU │☀️│ CLEAR SKY │ 80.3°F│ 63.5°F│ 10% │ ○ │
259
+ └──────┴──┴────────────────────┴───────┴───────┴───────┴────────┘
166
260
  ```
167
- Chicago, Illinois Weather
168
- ☀️ Conditions: Mainly clear
169
- 🌡️ Temperature: 75.2°F
170
- 🤔 Real Feel: 78.5°F
171
- 💨 Wind Speed: 12.4 mph
172
- 💧 Humidity: 65%
173
- ☔ Precip Chance: 30% (6h) | Light rain likely
174
- 🌅 Sunrise: 6:29 AM
175
- 🌇 Sunset: 5:37 PM
176
- ☀️ UV Index: 6.5 (High)
177
- 💨 Wind Alert: ⚠️ Gusts up to 25 mph
178
- 😷 Air Quality: 45 (Good)
179
-
180
- ↑ 5.2°F warmer than yesterday
181
-
182
- Preparation Guidance:
183
- • 🧥 Light jacket
184
- • 🧴 Sunscreen recommended
185
- • 🕶️ Sunglasses recommended
186
-
187
- 7-Day Forecast — Chicago, Illinois
188
- Day Conditions High Low Rain% UV
189
- Today ☁️ Overcast 78.7°F 63.9°F 30% 7.2
190
- Tue Apr 1 ⛅ Partly cloudy 82.4°F 65.4°F 20% 8.1
191
- Wed Apr 2 🌦️ Light drizzle 76.8°F 60.9°F 45% 5.8
192
- Thu Apr 3 ☀️ Clear sky 80.3°F 63.5°F 10% 8.5
193
- Fri Apr 4 ☀️ Clear sky 83.6°F 67.1°F 5% 9.0
194
- Sat Apr 5 ⛅ Partly cloudy 79.8°F 64.9°F 15% 7.8
195
- Sun Apr 6 🌤️ Mainly clear 81.2°F 66.3°F 10% 8.3
196
261
  ```
197
262
 
198
263
  ## 🛠 Tech Stack
@@ -212,6 +277,15 @@ Preparation Guidance:
212
277
  | `config.py` | Persistent home city configuration |
213
278
  | Enhanced `logic.py` | Preparation guidance, UV monitoring, gust alerts |
214
279
  | Updated `ui.py` | Contextual display of insights |
280
+ | **v1.2.0 Features** | **Security & Configuration** |
281
+ | Configurable API Endpoints | Environment variable support for custom APIs |
282
+ | Enhanced Error Handling | Specific exception catching with timeouts |
283
+ | Timezone Support | Optional `pytz` dependency for local time display |
284
+ | **v1.3.0 Features** | **Industrial Aesthetic** |
285
+ | Industrial UI Design | Retro-futuristic weather observatory dashboard |
286
+ | Visual Gauges | Temperature and humidity gauge visualizations |
287
+ | Severity Indicators | Weather condition severity classification |
288
+ | Enhanced Typography | Heavy borders, uppercase labels, status columns |
215
289
 
216
290
  ## 🔒 Security
217
291
 
@@ -235,6 +309,7 @@ All security scans are integrated into the CI/CD pipeline and run on every push,
235
309
  ✅ **Phase 5 Complete** — Testing & Reliability
236
310
  ✅ **Phase 6 Complete** — Distribution (PyPI, Homebrew)
237
311
  ✅ **Phase 7 Complete** — Intuition & Analysis (v1.1.0)
312
+ ✅ **v1.2.0 Complete** — Security & Configuration Enhancements
238
313
  Refer to [ROADMAP.md](ROADMAP.md) and [CHANGELOG.md](CHANGELOG.md) for details.
239
314
 
240
315
  ## 🤝 Contributing
@@ -3,7 +3,7 @@
3
3
  ![CI](https://github.com/KnowOneActual/isobar-cli/actions/workflows/ci.yml/badge.svg)
4
4
  ![Coverage](https://img.shields.io/badge/coverage-98%25-green)
5
5
  [![PyPI version](https://badge.fury.io/py/isobar-cli.svg)](https://badge.fury.io/py/isobar-cli)
6
- ![Version](https://img.shields.io/badge/version-1.0.1-blue)
6
+ ![Version](https://img.shields.io/badge/version-1.3.0-blue)
7
7
  ![Ruff](https://img.shields.io/badge/linting-ruff-purple)
8
8
  ![Python](https://img.shields.io/badge/python-3.8%2B-blue)
9
9
  ![License](https://img.shields.io/badge/license-MIT-green)
@@ -21,11 +21,13 @@ Most weather apps overwhelm with data. Isobar strips away everything except what
21
21
  - **Essential over comprehensive** — Show Real Feel, not 47 data points.
22
22
  - **Terminal-native** — Built for quick checks within a developer workflow.
23
23
  - **Zero friction** — No API keys or configuration files required.
24
- - **Information density** — Clean, borderless UI for maximum readability.
24
+ - **Information density** — Industrial dashboard UI for maximum readability.
25
25
  - **Intentional features** — Each feature must answer: *"Does this help someone understand what it feels like outside?"*
26
+ - **Distinctive aesthetic** — Retro-futuristic industrial styling that avoids generic "AI slop"
26
27
 
27
28
  ## ✨ Features
28
29
 
30
+ - **Industrial Aesthetic** — Retro-futuristic weather observatory dashboard with brutalist styling 🏭
29
31
  - **Auto-Location** — `isobar` detects the city automatically 🌍
30
32
  - **Weather Condition Icons** — WMO-standard emoji + plain-English description (☀️ Clear sky, 🌨️ Moderate snow, ⛈️ Thunderstorm)
31
33
  - **Real Feel** — Apparent temperature metrics (what it *actually* feels like).
@@ -42,12 +44,16 @@ Most weather apps overwhelm with data. Isobar strips away everything except what
42
44
  - **Metric Support** — `--metric` or `-m` for Celsius, km/h, and mm.
43
45
  - **No API Keys** — Free Open-Meteo and ip-api.com.
44
46
  - **Zero Config** — Works instantly after installation.
47
+ - **Visual Gauges** — Temperature and humidity gauge visualizations 📊
48
+ - **Severity Indicators** — Weather condition severity icons (⚡, ▲, ●, ○, ◇)
49
+ - **Wind Categories** — Descriptive wind speed classifications (CALM, LIGHT, GENTLE, etc.)
50
+ - **Industrial Styling** — Heavy borders, uppercase labels, status columns
45
51
  - **Phase 7: Intuition & Analysis** — Higher-level context and automated insights:
46
- - **Preparation Guidance** — Clothing and gear suggestions based on conditions 🧥☂️🧴
52
+ - **Preparation Guidance** — Clothing and gear suggestions with priority levels 🧥☂️🧴
47
53
  - **Temporal Context** — Comparison with previous day conditions 📈
48
54
  - **UV Index Monitoring** — Sun protection guidance with intensity levels ☀️
49
55
  - **Wind Gust Alerts** — Highlighting of significant gust events 💨⚠️
50
- - **Home City Persistence** — Set a default city with `isobar home "Your City"` 🏠
56
+ - **Home City Persistence** — Set a default city with `isobar home "Your City"` 🏠 *(Note: Due to a Typer limitation, this currently shows weather for "Home, Kansas" instead of setting home city. Manual config editing required.)*
51
57
 
52
58
  ## 🚀 Installation
53
59
 
@@ -91,12 +97,16 @@ isobar London Tokyo Paris # Multiple cities
91
97
  isobar "New York" # Use quotes for multi-word cities
92
98
 
93
99
  # Hourly outlook (next 12h)
94
- isobar --hourly
95
- isobar -H
100
+ isobar --hourly Chicago
101
+ isobar -H Chicago
96
102
 
97
103
  # 7-day forecast
98
- isobar --forecast
99
- isobar -f
104
+ isobar --forecast Chicago
105
+ isobar -f Chicago
106
+
107
+ # Note: Flags must come before city names
108
+ # ✅ isobar -H Chicago
109
+ # ❌ isobar Chicago -H (treats "-H" as a city name)
100
110
  isobar "San Francisco" --forecast
101
111
  isobar -f Sydney
102
112
 
@@ -112,6 +122,42 @@ isobar home --clear # Clear home city
112
122
  isobar # Uses home city if set (otherwise auto-detects)
113
123
  ```
114
124
 
125
+ ## ⚙️ Configuration
126
+
127
+ Isobar supports configuration via environment variables for advanced use cases:
128
+
129
+ ### API Endpoint Configuration
130
+ Customize API endpoints for different weather providers or testing:
131
+
132
+ ```bash
133
+ # Use custom weather APIs
134
+ export ISOBAR_GEOCODING_URL="https://custom-geocoding-api.example.com/v1/search"
135
+ export ISOBAR_WEATHER_URL="https://custom-weather-api.example.com/v1/forecast"
136
+ export ISOBAR_AQI_URL="https://custom-aqi-api.example.com/v1/air-quality"
137
+
138
+ # Run with custom endpoints
139
+ isobar "New York"
140
+ ```
141
+
142
+ ### Timezone Support
143
+ For enhanced timezone accuracy (optional):
144
+
145
+ ```bash
146
+ # Install optional timezone support
147
+ pip install isobar-cli[timezone]
148
+
149
+ # Sunrise/sunset will now display in local timezone
150
+ isobar London
151
+ ```
152
+
153
+ ### Debug Mode
154
+ Enable debug logging to stderr:
155
+
156
+ ```bash
157
+ # View API errors and debugging information
158
+ isobar "Test City" 2> debug.log
159
+ ```
160
+
115
161
  ## ⌨️ Shell Completion
116
162
 
117
163
  Isobar supports tab-completion for city names. To enable it for a shell:
@@ -130,36 +176,53 @@ isobar --install-completion bash
130
176
 
131
177
  ## 🖥️ Example Output
132
178
 
179
+ ### Industrial Aesthetic (v1.3.0+)
180
+
181
+ ```
182
+ ┌─ WEATHER OBSERVATORY ─┐
183
+ CHICAGO
184
+ ┌─────┬──────────────────────┬────────────────┬────────────────┐
185
+ │ │ METRIC │ READING │ STATUS │
186
+ ├─────┼──────────────────────┼────────────────┼────────────────┤
187
+ │ ☀️ │ CONDITIONS │ MAINLY CLEAR │ ◇ │
188
+ │ 🌡️ │ TEMPERATURE │ 75.2°F │ [███░░░░░░░] │
189
+ │ 🤔 │ REAL FEEL │ 78.5°F │ ▲ 3.3°F │
190
+ │ 💨 │ WIND SPEED │ 12.4 mph │ GENTLE │
191
+ │ 💧 │ HUMIDITY │ 65% │ [▓▓▓░░] │
192
+ │ 😷 │ AIR QUALITY │ 45 │ GOOD ◇ │
193
+ │ ☔ │ PRECIPITATION │ 30% (6h) │ [▓░░] │
194
+ │ │ FORECAST │ LIGHT RAIN LIKELY │ │
195
+ │ 🌅 │ SUNRISE │ 06:29 │ DAWN │
196
+ │ 🌇 │ SUNSET │ 17:37 │ DUSK │
197
+ │ ☀️ │ UV INDEX │ 6.5 │ HIGH ☀️☀️☀️ │
198
+ │ ⚡ │ GUST ALERT │ 25 mph │ ⚠️ SEVERE │
199
+ └─────┴──────────────────────┴────────────────┴────────────────┘
200
+
201
+ ┌─ TREND ANALYSIS ─┐
202
+ ↑ 5.2°F WARMER THAN YESTERDAY
203
+ └──────────────────┘
204
+
205
+ ┌─ PREPARATION PROTOCOL ─┐
206
+ ⚠️ HIGH PRIORITY
207
+ ▶ Wind gusts up to 25 mph - secure loose items
208
+ ▲ RECOMMENDED
209
+ ▶ Light jacket recommended
210
+ ▶ Sunscreen recommended (UV: High)
211
+ ○ ADVISORY
212
+ ▶ Sunglasses recommended for glare
213
+ └─────────────────────────┘
214
+
215
+ ┌─ FORECAST PANEL ─┐
216
+ CHICAGO
217
+ ┌──────┬──┬────────────────────┬───────┬───────┬───────┬────────┐
218
+ │ DAY │ │ CONDITIONS │ HIGH │ LOW │ RAIN% │ STATUS │
219
+ ├──────┼──┼────────────────────┼───────┼───────┼───────┼────────┤
220
+ │ TODAY│☀️│ MAINLY CLEAR │ 78.7°F│ 63.9°F│ 30% │ ○ │
221
+ │ TUE │⛅│ PARTLY CLOUDY │ 82.4°F│ 65.4°F│ 20% │ ○ │
222
+ │ WED │🌦️│ LIGHT DRIZZLE │ 76.8°F│ 60.9°F│ 45% │ ● │
223
+ │ THU │☀️│ CLEAR SKY │ 80.3°F│ 63.5°F│ 10% │ ○ │
224
+ └──────┴──┴────────────────────┴───────┴───────┴───────┴────────┘
133
225
  ```
134
- Chicago, Illinois Weather
135
- ☀️ Conditions: Mainly clear
136
- 🌡️ Temperature: 75.2°F
137
- 🤔 Real Feel: 78.5°F
138
- 💨 Wind Speed: 12.4 mph
139
- 💧 Humidity: 65%
140
- ☔ Precip Chance: 30% (6h) | Light rain likely
141
- 🌅 Sunrise: 6:29 AM
142
- 🌇 Sunset: 5:37 PM
143
- ☀️ UV Index: 6.5 (High)
144
- 💨 Wind Alert: ⚠️ Gusts up to 25 mph
145
- 😷 Air Quality: 45 (Good)
146
-
147
- ↑ 5.2°F warmer than yesterday
148
-
149
- Preparation Guidance:
150
- • 🧥 Light jacket
151
- • 🧴 Sunscreen recommended
152
- • 🕶️ Sunglasses recommended
153
-
154
- 7-Day Forecast — Chicago, Illinois
155
- Day Conditions High Low Rain% UV
156
- Today ☁️ Overcast 78.7°F 63.9°F 30% 7.2
157
- Tue Apr 1 ⛅ Partly cloudy 82.4°F 65.4°F 20% 8.1
158
- Wed Apr 2 🌦️ Light drizzle 76.8°F 60.9°F 45% 5.8
159
- Thu Apr 3 ☀️ Clear sky 80.3°F 63.5°F 10% 8.5
160
- Fri Apr 4 ☀️ Clear sky 83.6°F 67.1°F 5% 9.0
161
- Sat Apr 5 ⛅ Partly cloudy 79.8°F 64.9°F 15% 7.8
162
- Sun Apr 6 🌤️ Mainly clear 81.2°F 66.3°F 10% 8.3
163
226
  ```
164
227
 
165
228
  ## 🛠 Tech Stack
@@ -179,6 +242,15 @@ Preparation Guidance:
179
242
  | `config.py` | Persistent home city configuration |
180
243
  | Enhanced `logic.py` | Preparation guidance, UV monitoring, gust alerts |
181
244
  | Updated `ui.py` | Contextual display of insights |
245
+ | **v1.2.0 Features** | **Security & Configuration** |
246
+ | Configurable API Endpoints | Environment variable support for custom APIs |
247
+ | Enhanced Error Handling | Specific exception catching with timeouts |
248
+ | Timezone Support | Optional `pytz` dependency for local time display |
249
+ | **v1.3.0 Features** | **Industrial Aesthetic** |
250
+ | Industrial UI Design | Retro-futuristic weather observatory dashboard |
251
+ | Visual Gauges | Temperature and humidity gauge visualizations |
252
+ | Severity Indicators | Weather condition severity classification |
253
+ | Enhanced Typography | Heavy borders, uppercase labels, status columns |
182
254
 
183
255
  ## 🔒 Security
184
256
 
@@ -202,6 +274,7 @@ All security scans are integrated into the CI/CD pipeline and run on every push,
202
274
  ✅ **Phase 5 Complete** — Testing & Reliability
203
275
  ✅ **Phase 6 Complete** — Distribution (PyPI, Homebrew)
204
276
  ✅ **Phase 7 Complete** — Intuition & Analysis (v1.1.0)
277
+ ✅ **v1.2.0 Complete** — Security & Configuration Enhancements
205
278
  Refer to [ROADMAP.md](ROADMAP.md) and [CHANGELOG.md](CHANGELOG.md) for details.
206
279
 
207
280
  ## 🤝 Contributing
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "isobar-cli"
7
- version = "1.1.2"
8
- description = "A visually pleasing terminal weather tool focusing on Real Feel and Windchill."
7
+ version = "1.3.0"
8
+ description = "A terminal weather tool with industrial aesthetic, focusing on Real Feel and Windchill."
9
9
  authors = [
10
10
  { name="Beau Bremer / KnowOneActual" },
11
11
  ]
@@ -27,9 +27,9 @@ dependencies = [
27
27
  "rich>=13.0.0",
28
28
  "requests>=2.31.0",
29
29
  "typer>=0.9.0",
30
- "timezonefinder>=6.0.0",
31
- ]
32
- requires-python = ">=3.8"
30
+ "timezonefinder>=6.0.0",
31
+ ]
32
+ requires-python = ">=3.8"
33
33
 
34
34
  [project.urls]
35
35
  Homepage = "https://github.com/KnowOneActual/isobar-cli"
@@ -39,11 +39,14 @@ dependencies = [
39
39
 
40
40
  [project.optional-dependencies]
41
41
 
42
- test = [
43
- "pytest>=7.0.0",
44
- "requests-mock>=1.11.0",
45
- "pytest-cov>=4.1.0",
46
- ]
42
+ test = [
43
+ "pytest>=7.0.0",
44
+ "requests-mock>=1.11.0",
45
+ "pytest-cov>=4.1.0",
46
+ ]
47
+ timezone = [
48
+ "pytz>=2024.1",
49
+ ]
47
50
 
48
51
  [project.scripts]
49
52
  isobar = "isobar_cli.main:app" # This allows you to type 'isobar' in the terminal to run it
@@ -0,0 +1 @@
1
+ __version__ = "1.3.0"
@@ -7,6 +7,7 @@ from typing import Optional
7
7
  import requests
8
8
  from timezonefinder import TimezoneFinder
9
9
 
10
+ from .config import get_aqi_url, get_geocoding_url, get_weather_url
10
11
  from .logic import format_time
11
12
  from .models import ForecastDay, HourlyForecast, UnitSystem, WeatherData, WeatherUnits
12
13
 
@@ -15,22 +16,39 @@ CACHE_DIR.mkdir(parents=True, exist_ok=True)
15
16
 
16
17
 
17
18
  class GeocodingClient:
18
- BASE_URL = "https://geocoding-api.open-meteo.com/v1/search"
19
+ @classmethod
20
+ def get_base_url(cls) -> str:
21
+ """Get geocoding API URL from configuration."""
22
+ return get_geocoding_url()
19
23
 
20
24
  @classmethod
21
25
  def search(cls, city: str, count: int = 1) -> list[dict]:
22
26
  try:
23
27
  response = requests.get(
24
- f"{cls.BASE_URL}?name={city}&count={count}&format=json"
28
+ f"{cls.get_base_url()}?name={city}&count={count}&format=json",
29
+ timeout=10,
25
30
  )
26
31
  response.raise_for_status()
27
32
  return response.json().get("results", [])
28
- except Exception:
33
+ except requests.exceptions.RequestException as e:
34
+ # Log error for debugging but don't crash
35
+ import sys
36
+
37
+ print(f"Geocoding error for '{city}': {e}", file=sys.stderr)
38
+ return []
39
+ except Exception as e:
40
+ # Catch-all for unexpected errors
41
+ import sys
42
+
43
+ print(f"Unexpected geocoding error for '{city}': {e}", file=sys.stderr)
29
44
  return []
30
45
 
31
46
 
32
47
  class WeatherClient:
33
- BASE_URL = "https://api.open-meteo.com/v1/forecast"
48
+ @classmethod
49
+ def get_base_url(cls) -> str:
50
+ """Get weather API URL from configuration."""
51
+ return get_weather_url()
34
52
 
35
53
  def __init__(self, lat: float, lon: float, timezone: str, metric: bool = False):
36
54
  self.lat = lat
@@ -59,23 +77,37 @@ class WeatherClient:
59
77
  "forecast_days": 7,
60
78
  }
61
79
 
62
- response = requests.get(self.BASE_URL, params=params)
80
+ response = requests.get(self.get_base_url(), params=params, timeout=15)
63
81
  response.raise_for_status()
64
82
  return response.json()
65
83
 
66
84
 
67
85
  class AirQualityClient:
68
- BASE_URL = "https://air-quality-api.open-meteo.com/v1/air-quality"
86
+ @classmethod
87
+ def get_base_url(cls) -> str:
88
+ """Get air quality API URL from configuration."""
89
+ return get_aqi_url()
69
90
 
70
91
  @classmethod
71
92
  def get_aqi(cls, lat: float, lon: float) -> Optional[int]:
72
93
  try:
73
94
  response = requests.get(
74
- f"{cls.BASE_URL}?latitude={lat}&longitude={lon}&current=us_aqi"
95
+ f"{cls.get_base_url()}?latitude={lat}&longitude={lon}&current=us_aqi",
96
+ timeout=10,
75
97
  )
76
98
  response.raise_for_status()
77
99
  return response.json().get("current", {}).get("us_aqi")
78
- except Exception:
100
+ except requests.exceptions.RequestException as e:
101
+ # Log error for debugging but don't crash
102
+ import sys
103
+
104
+ print(f"AQI error for ({lat},{lon}): {e}", file=sys.stderr)
105
+ return None
106
+ except Exception as e:
107
+ # Catch-all for unexpected errors
108
+ import sys
109
+
110
+ print(f"Unexpected AQI error for ({lat},{lon}): {e}", file=sys.stderr)
79
111
  return None
80
112
 
81
113
 
@@ -207,8 +239,8 @@ def get_weather_data(city: str, metric: bool = False) -> Optional[WeatherData]:
207
239
  precip_prob=round(avg_precip_prob),
208
240
  rainfall=next_6h_rain,
209
241
  snowfall=next_6h_snow,
210
- sunrise=format_time(daily["sunrise"][0]),
211
- sunset=format_time(daily["sunset"][0]),
242
+ sunrise=format_time(daily["sunrise"][0], timezone),
243
+ sunset=format_time(daily["sunset"][0], timezone),
212
244
  forecast=forecast,
213
245
  hourly=hourly_forecast,
214
246
  units=weather_client.units,
@@ -1,12 +1,18 @@
1
1
  """Configuration module for Isobar CLI persistent settings."""
2
2
 
3
3
  import json
4
+ import os
4
5
  from pathlib import Path
5
6
  from typing import Optional
6
7
 
7
8
  CONFIG_DIR = Path.home() / ".config" / "isobar"
8
9
  CONFIG_FILE = CONFIG_DIR / "config.json"
9
10
 
11
+ # Default API endpoints (can be overridden by environment variables)
12
+ DEFAULT_GEOCODING_URL = "https://geocoding-api.open-meteo.com/v1/search"
13
+ DEFAULT_WEATHER_URL = "https://api.open-meteo.com/v1/forecast"
14
+ DEFAULT_AQI_URL = "https://air-quality-api.open-meteo.com/v1/air-quality"
15
+
10
16
 
11
17
  def ensure_config_dir() -> None:
12
18
  """Create config directory if it doesn't exist."""
@@ -72,3 +78,18 @@ def clear_home_city() -> None:
72
78
  def get_config_path() -> Path:
73
79
  """Get the path to the config file (for debugging/info)."""
74
80
  return CONFIG_FILE
81
+
82
+
83
+ def get_geocoding_url() -> str:
84
+ """Get geocoding API URL from environment or default."""
85
+ return os.environ.get("ISOBAR_GEOCODING_URL", DEFAULT_GEOCODING_URL)
86
+
87
+
88
+ def get_weather_url() -> str:
89
+ """Get weather API URL from environment or default."""
90
+ return os.environ.get("ISOBAR_WEATHER_URL", DEFAULT_WEATHER_URL)
91
+
92
+
93
+ def get_aqi_url() -> str:
94
+ """Get air quality API URL from environment or default."""
95
+ return os.environ.get("ISOBAR_AQI_URL", DEFAULT_AQI_URL)