wxbrief 0.4.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.
- wxbrief-0.4.0/LICENSE +21 -0
- wxbrief-0.4.0/PKG-INFO +185 -0
- wxbrief-0.4.0/README.md +140 -0
- wxbrief-0.4.0/pyproject.toml +119 -0
- wxbrief-0.4.0/setup.cfg +4 -0
- wxbrief-0.4.0/tests/test_app_i18n.py +218 -0
- wxbrief-0.4.0/tests/test_app_smoke.py +552 -0
- wxbrief-0.4.0/tests/test_app_themes.py +267 -0
- wxbrief-0.4.0/tests/test_awc_crosscheck.py +352 -0
- wxbrief-0.4.0/tests/test_awc_taf_crosscheck.py +499 -0
- wxbrief-0.4.0/tests/test_cache_state.py +144 -0
- wxbrief-0.4.0/tests/test_calc.py +315 -0
- wxbrief-0.4.0/tests/test_cancelled_groups.py +143 -0
- wxbrief-0.4.0/tests/test_cli.py +331 -0
- wxbrief-0.4.0/tests/test_cli_polish.py +48 -0
- wxbrief-0.4.0/tests/test_client.py +531 -0
- wxbrief-0.4.0/tests/test_clipboard.py +81 -0
- wxbrief-0.4.0/tests/test_colorstate.py +220 -0
- wxbrief-0.4.0/tests/test_context.py +41 -0
- wxbrief-0.4.0/tests/test_controls.py +71 -0
- wxbrief-0.4.0/tests/test_data_files.py +203 -0
- wxbrief-0.4.0/tests/test_demo_mode.py +63 -0
- wxbrief-0.4.0/tests/test_derived.py +311 -0
- wxbrief-0.4.0/tests/test_discord.py +382 -0
- wxbrief-0.4.0/tests/test_first_run_input.py +169 -0
- wxbrief-0.4.0/tests/test_flightcat.py +306 -0
- wxbrief-0.4.0/tests/test_footer.py +126 -0
- wxbrief-0.4.0/tests/test_fuzz.py +358 -0
- wxbrief-0.4.0/tests/test_get.py +136 -0
- wxbrief-0.4.0/tests/test_goldens.py +61 -0
- wxbrief-0.4.0/tests/test_groups.py +452 -0
- wxbrief-0.4.0/tests/test_hypothesis_feeds.py +57 -0
- wxbrief-0.4.0/tests/test_i18n.py +200 -0
- wxbrief-0.4.0/tests/test_i18n_fixes.py +88 -0
- wxbrief-0.4.0/tests/test_i18n_locales.py +243 -0
- wxbrief-0.4.0/tests/test_last_polish.py +159 -0
- wxbrief-0.4.0/tests/test_layout.py +282 -0
- wxbrief-0.4.0/tests/test_limits.py +91 -0
- wxbrief-0.4.0/tests/test_locale_grammar.py +81 -0
- wxbrief-0.4.0/tests/test_metar.py +371 -0
- wxbrief-0.4.0/tests/test_phrases.py +382 -0
- wxbrief-0.4.0/tests/test_phrases_tail.py +556 -0
- wxbrief-0.4.0/tests/test_polish.py +230 -0
- wxbrief-0.4.0/tests/test_poll.py +425 -0
- wxbrief-0.4.0/tests/test_remarks.py +498 -0
- wxbrief-0.4.0/tests/test_render.py +277 -0
- wxbrief-0.4.0/tests/test_robustness.py +678 -0
- wxbrief-0.4.0/tests/test_round5.py +98 -0
- wxbrief-0.4.0/tests/test_screenshot_colour.py +53 -0
- wxbrief-0.4.0/tests/test_selftest.py +25 -0
- wxbrief-0.4.0/tests/test_smoke.py +39 -0
- wxbrief-0.4.0/tests/test_snapshots.py +43 -0
- wxbrief-0.4.0/tests/test_solar.py +78 -0
- wxbrief-0.4.0/tests/test_split.py +215 -0
- wxbrief-0.4.0/tests/test_strip.py +117 -0
- wxbrief-0.4.0/tests/test_taf.py +403 -0
- wxbrief-0.4.0/tests/test_taf_goldens.py +93 -0
- wxbrief-0.4.0/tests/test_tafgroups.py +243 -0
- wxbrief-0.4.0/tests/test_tail.py +560 -0
- wxbrief-0.4.0/tests/test_themes.py +209 -0
- wxbrief-0.4.0/tests/test_timeline.py +336 -0
- wxbrief-0.4.0/tests/test_timeline_ui.py +392 -0
- wxbrief-0.4.0/tests/test_times.py +79 -0
- wxbrief-0.4.0/tests/test_tokens.py +87 -0
- wxbrief-0.4.0/tests/test_ui_lifecycle.py +322 -0
- wxbrief-0.4.0/tests/test_ui_round2.py +124 -0
- wxbrief-0.4.0/tests/test_ui_round3.py +126 -0
- wxbrief-0.4.0/tests/test_ui_round4.py +242 -0
- wxbrief-0.4.0/tests/test_units.py +58 -0
- wxbrief-0.4.0/tests/test_ux_polish.py +146 -0
- wxbrief-0.4.0/wxbrief/__init__.py +4 -0
- wxbrief-0.4.0/wxbrief/__main__.py +359 -0
- wxbrief-0.4.0/wxbrief/app.py +497 -0
- wxbrief-0.4.0/wxbrief/calc/__init__.py +24 -0
- wxbrief-0.4.0/wxbrief/calc/airport.py +35 -0
- wxbrief-0.4.0/wxbrief/calc/altitude.py +87 -0
- wxbrief-0.4.0/wxbrief/calc/spread.py +42 -0
- wxbrief-0.4.0/wxbrief/calc/wind.py +75 -0
- wxbrief-0.4.0/wxbrief/clipboard.py +56 -0
- wxbrief-0.4.0/wxbrief/config.py +268 -0
- wxbrief-0.4.0/wxbrief/data/__init__.py +1 -0
- wxbrief-0.4.0/wxbrief/data/awc.py +254 -0
- wxbrief-0.4.0/wxbrief/data/cache.py +87 -0
- wxbrief-0.4.0/wxbrief/data/demo/CYYZ.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/EGLL.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/ETHB.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/KDEN.txt +4 -0
- wxbrief-0.4.0/wxbrief/data/demo/NZSP.txt +4 -0
- wxbrief-0.4.0/wxbrief/data/demo/RJTT.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/SBGR.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/UUEE.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/VIDP.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo/YSSY.txt +3 -0
- wxbrief-0.4.0/wxbrief/data/demo.py +66 -0
- wxbrief-0.4.0/wxbrief/data/models.py +233 -0
- wxbrief-0.4.0/wxbrief/data/poll.py +273 -0
- wxbrief-0.4.0/wxbrief/data/stations.json.gz +0 -0
- wxbrief-0.4.0/wxbrief/data/stations.py +156 -0
- wxbrief-0.4.0/wxbrief/decode/__init__.py +1 -0
- wxbrief-0.4.0/wxbrief/decode/colorstate.py +114 -0
- wxbrief-0.4.0/wxbrief/decode/derived.py +308 -0
- wxbrief-0.4.0/wxbrief/decode/detect.py +71 -0
- wxbrief-0.4.0/wxbrief/decode/flightcat.py +110 -0
- wxbrief-0.4.0/wxbrief/decode/groups/__init__.py +6 -0
- wxbrief-0.4.0/wxbrief/decode/groups/colorstate.py +76 -0
- wxbrief-0.4.0/wxbrief/decode/groups/header.py +63 -0
- wxbrief-0.4.0/wxbrief/decode/groups/pressure.py +48 -0
- wxbrief-0.4.0/wxbrief/decode/groups/recentwx.py +50 -0
- wxbrief-0.4.0/wxbrief/decode/groups/runwaystate.py +159 -0
- wxbrief-0.4.0/wxbrief/decode/groups/rvr.py +42 -0
- wxbrief-0.4.0/wxbrief/decode/groups/seastate.py +40 -0
- wxbrief-0.4.0/wxbrief/decode/groups/sky.py +31 -0
- wxbrief-0.4.0/wxbrief/decode/groups/tafgroups.py +303 -0
- wxbrief-0.4.0/wxbrief/decode/groups/tail.py +94 -0
- wxbrief-0.4.0/wxbrief/decode/groups/tempdew.py +36 -0
- wxbrief-0.4.0/wxbrief/decode/groups/trend.py +116 -0
- wxbrief-0.4.0/wxbrief/decode/groups/visibility.py +141 -0
- wxbrief-0.4.0/wxbrief/decode/groups/weather.py +45 -0
- wxbrief-0.4.0/wxbrief/decode/groups/wind.py +78 -0
- wxbrief-0.4.0/wxbrief/decode/groups/windshear.py +50 -0
- wxbrief-0.4.0/wxbrief/decode/metar.py +415 -0
- wxbrief-0.4.0/wxbrief/decode/model.py +1227 -0
- wxbrief-0.4.0/wxbrief/decode/remarks.py +891 -0
- wxbrief-0.4.0/wxbrief/decode/split.py +224 -0
- wxbrief-0.4.0/wxbrief/decode/tables.py +497 -0
- wxbrief-0.4.0/wxbrief/decode/taf.py +507 -0
- wxbrief-0.4.0/wxbrief/decode/timeline.py +307 -0
- wxbrief-0.4.0/wxbrief/decode/times.py +160 -0
- wxbrief-0.4.0/wxbrief/decode/tokens.py +109 -0
- wxbrief-0.4.0/wxbrief/decode/units.py +162 -0
- wxbrief-0.4.0/wxbrief/getcmd.py +149 -0
- wxbrief-0.4.0/wxbrief/i18n/__init__.py +200 -0
- wxbrief-0.4.0/wxbrief/i18n/keys.py +822 -0
- wxbrief-0.4.0/wxbrief/i18n/locales/de.toml +999 -0
- wxbrief-0.4.0/wxbrief/i18n/locales/en.toml +992 -0
- wxbrief-0.4.0/wxbrief/i18n/locales/es.toml +992 -0
- wxbrief-0.4.0/wxbrief/i18n/locales/fr.toml +991 -0
- wxbrief-0.4.0/wxbrief/i18n/locales/pt.toml +991 -0
- wxbrief-0.4.0/wxbrief/i18n/numbers.py +62 -0
- wxbrief-0.4.0/wxbrief/i18n/plurals.py +35 -0
- wxbrief-0.4.0/wxbrief/render/__init__.py +1 -0
- wxbrief-0.4.0/wxbrief/render/discord.py +504 -0
- wxbrief-0.4.0/wxbrief/render/highlight.py +82 -0
- wxbrief-0.4.0/wxbrief/render/jsonout.py +39 -0
- wxbrief-0.4.0/wxbrief/render/measure.py +191 -0
- wxbrief-0.4.0/wxbrief/render/pairs.py +197 -0
- wxbrief-0.4.0/wxbrief/render/palette.py +158 -0
- wxbrief-0.4.0/wxbrief/render/phrases.py +947 -0
- wxbrief-0.4.0/wxbrief/render/plain.py +295 -0
- wxbrief-0.4.0/wxbrief/render/richtext.py +108 -0
- wxbrief-0.4.0/wxbrief/selftest.py +109 -0
- wxbrief-0.4.0/wxbrief/solar.py +46 -0
- wxbrief-0.4.0/wxbrief/state.py +319 -0
- wxbrief-0.4.0/wxbrief/ui/__init__.py +1 -0
- wxbrief-0.4.0/wxbrief/ui/app.tcss +382 -0
- wxbrief-0.4.0/wxbrief/ui/bindings.py +64 -0
- wxbrief-0.4.0/wxbrief/ui/commands.py +127 -0
- wxbrief-0.4.0/wxbrief/ui/context.py +88 -0
- wxbrief-0.4.0/wxbrief/ui/copying.py +77 -0
- wxbrief-0.4.0/wxbrief/ui/fcat.py +57 -0
- wxbrief-0.4.0/wxbrief/ui/glyphs.py +29 -0
- wxbrief-0.4.0/wxbrief/ui/screens/__init__.py +1 -0
- wxbrief-0.4.0/wxbrief/ui/screens/add_station.py +116 -0
- wxbrief-0.4.0/wxbrief/ui/screens/base.py +29 -0
- wxbrief-0.4.0/wxbrief/ui/screens/briefing.py +260 -0
- wxbrief-0.4.0/wxbrief/ui/screens/help.py +79 -0
- wxbrief-0.4.0/wxbrief/ui/screens/paste.py +156 -0
- wxbrief-0.4.0/wxbrief/ui/screens/settings.py +76 -0
- wxbrief-0.4.0/wxbrief/ui/screens/station_detail.py +63 -0
- wxbrief-0.4.0/wxbrief/ui/screens/theme_picker.py +56 -0
- wxbrief-0.4.0/wxbrief/ui/screens/too_small.py +46 -0
- wxbrief-0.4.0/wxbrief/ui/strip.py +105 -0
- wxbrief-0.4.0/wxbrief/ui/style.py +58 -0
- wxbrief-0.4.0/wxbrief/ui/themes/__init__.py +11 -0
- wxbrief-0.4.0/wxbrief/ui/themes/aviation.py +104 -0
- wxbrief-0.4.0/wxbrief/ui/themes/semantic.py +70 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/__init__.py +1 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/detail.py +507 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/key_bar.py +61 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/period_detail.py +185 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/station_card.py +109 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/station_grid.py +170 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/station_list.py +157 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/status_bar.py +95 -0
- wxbrief-0.4.0/wxbrief/ui/widgets/taf_timeline.py +298 -0
- wxbrief-0.4.0/wxbrief/ui/wrap.py +61 -0
- wxbrief-0.4.0/wxbrief.egg-info/PKG-INFO +185 -0
- wxbrief-0.4.0/wxbrief.egg-info/SOURCES.txt +190 -0
- wxbrief-0.4.0/wxbrief.egg-info/dependency_links.txt +1 -0
- wxbrief-0.4.0/wxbrief.egg-info/entry_points.txt +2 -0
- wxbrief-0.4.0/wxbrief.egg-info/requires.txt +34 -0
- wxbrief-0.4.0/wxbrief.egg-info/top_level.txt +1 -0
wxbrief-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bill Kane
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wxbrief-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wxbrief
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Terminal METAR/TAF briefing with colorways and plain-language translation
|
|
5
|
+
Author: Bill Kane
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/WPTK/wxbrief
|
|
8
|
+
Project-URL: Issues, https://github.com/WPTK/wxbrief/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/WPTK/wxbrief/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: metar,taf,aviation,weather,tui,terminal,textual
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: textual<9,>=8.2
|
|
15
|
+
Requires-Dist: httpx<1,>=0.28
|
|
16
|
+
Requires-Dist: hishel[async]<2,>=1.4
|
|
17
|
+
Requires-Dist: anysqlite<1,>=0.0.5
|
|
18
|
+
Requires-Dist: stamina<27,>=26
|
|
19
|
+
Requires-Dist: platformdirs<5,>=4
|
|
20
|
+
Requires-Dist: tomli-w<2,>=1
|
|
21
|
+
Requires-Dist: pyperclip<2,>=1.9
|
|
22
|
+
Requires-Dist: tzdata; sys_platform == "win32"
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
|
|
26
|
+
Requires-Dist: respx>=0.22; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-xdist>=3.6; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
|
|
29
|
+
Requires-Dist: psutil>=6; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
31
|
+
Requires-Dist: hypothesis>=6; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-textual-snapshot==1.1.*; extra == "dev"
|
|
33
|
+
Requires-Dist: timezonefinder<10,>=9; extra == "dev"
|
|
34
|
+
Requires-Dist: pyinstaller<7,>=6.22; extra == "dev"
|
|
35
|
+
Requires-Dist: build<2,>=1; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
37
|
+
Requires-Dist: pillow>=10; extra == "dev"
|
|
38
|
+
Requires-Dist: vulture>=2.14; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy>=1.13; extra == "dev"
|
|
40
|
+
Requires-Dist: types-pyperclip; extra == "dev"
|
|
41
|
+
Requires-Dist: tui-test==0.1.1; extra == "dev"
|
|
42
|
+
Provides-Extra: binary
|
|
43
|
+
Requires-Dist: tzdata>=2024.1; extra == "binary"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# wxbrief
|
|
47
|
+
|
|
48
|
+
[](https://github.com/WPTK/wxbrief/actions/workflows/ci.yml)
|
|
49
|
+
[](LICENSE)
|
|
50
|
+
|
|
51
|
+
A terminal app for reading METARs and TAFs. It fetches the reports from aviationweather.gov, decodes them with its own
|
|
52
|
+
parser, and shows each station with the raw report, a plain-language translation and a TAF timeline. The colours are
|
|
53
|
+
switchable, and the text is available in English, Spanish, French, German and Portuguese.
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
*Recorded from the real app running on its bundled `--demo` reports (fixed demo data, not live weather).*
|
|
58
|
+
|
|
59
|
+

|
|
60
|
+
|
|
61
|
+
Version 0.4.0. The project uses ZeroVer, so the version stays 0.x and anything may still change.
|
|
62
|
+
|
|
63
|
+
## What it does
|
|
64
|
+
|
|
65
|
+
- Watches a list of stations and refreshes their METAR/SPECI and TAF reports within a polling budget that stays under
|
|
66
|
+
the AWC rate limit. Reports are cached on disk.
|
|
67
|
+
- Decodes the body, trends, remarks (including colour states, runway state, wind shear and sea state) and TAF change
|
|
68
|
+
groups. Anything it cannot decode is shown as it was reported, not guessed.
|
|
69
|
+
- Shows a TAF timeline per station. A cursor moves through the periods and the period under it is decoded below.
|
|
70
|
+
- Has a list layout and a grid layout (`v` switches), and works down to 60 columns by 16 rows.
|
|
71
|
+
- Offers 18 colorways (`t` cycles them, `T` opens a picker with live preview). See [docs/themes.md](docs/themes.md).
|
|
72
|
+
- Decodes pasted reports offline (`p`).
|
|
73
|
+
- Copies a report as a Discord code block (`c`), or prints one from the command line.
|
|
74
|
+
- Prints plain text or JSON from the `decode` and `get` commands.
|
|
75
|
+
- Runs with no network at all in `--demo` mode, on ten bundled stations.
|
|
76
|
+
|
|
77
|
+
## What wxbrief is not
|
|
78
|
+
|
|
79
|
+
wxbrief is not a substitute for an official weather briefing, and not for flight planning alone. Get an official briefing
|
|
80
|
+
before you fly. The same notice is in `wxbrief --help` and the in-app help (`?`).
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
## Install
|
|
87
|
+
|
|
88
|
+
There is no PyPI package. Each [release](https://github.com/WPTK/wxbrief/releases) has these files:
|
|
89
|
+
|
|
90
|
+
| File | For |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `wxbrief-0.4.0-windows-x86_64.exe` | Windows, no Python needed |
|
|
93
|
+
| `wxbrief-0.4.0-linux-x86_64.tar.gz`, `wxbrief-0.4.0-linux-arm64.tar.gz` | Linux; the archive holds one `wxbrief` executable |
|
|
94
|
+
| `wxbrief-0.4.0-macos-arm64.tar.gz`, `wxbrief-0.4.0-macos-x86_64.tar.gz` | macOS; the archive holds one `wxbrief` executable |
|
|
95
|
+
| `wxbrief-0.4.0-py3-none-any.whl` | any platform with Python 3.12 or newer: `pip install wxbrief-0.4.0-py3-none-any.whl` |
|
|
96
|
+
| `SHA256SUMS` | checking the downloads; each file also has a build provenance attestation |
|
|
97
|
+
|
|
98
|
+
To run from source instead, you need Python 3.12 or newer:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
git clone https://github.com/WPTK/wxbrief.git
|
|
102
|
+
cd wxbrief
|
|
103
|
+
python -m venv .venv
|
|
104
|
+
.venv/bin/python -m pip install -e .
|
|
105
|
+
.venv/bin/wxbrief --version
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
On Windows the venv paths are `.venv\Scripts\python` and `.venv\Scripts\wxbrief`. The commands below assume `wxbrief` is
|
|
109
|
+
on your path; otherwise use `python -m wxbrief`.
|
|
110
|
+
|
|
111
|
+
## Usage
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
wxbrief --demo # ten bundled stations, offline
|
|
115
|
+
wxbrief KDEN EGLL ETHB # watch these stations for this run
|
|
116
|
+
wxbrief # your saved stations
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Press `?` in the app for the keys. The main ones:
|
|
120
|
+
|
|
121
|
+
| Key | Does |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `a`, `d` | add or remove a station (by ICAO, IATA or FAA code or by name) |
|
|
124
|
+
| `r` | refresh |
|
|
125
|
+
| `v` | list or grid |
|
|
126
|
+
| `1` `2` `3` | raw, decoded and forecast sections |
|
|
127
|
+
| `p` | paste METARs or TAFs and decode them |
|
|
128
|
+
| `c` | copy the report as a Discord block |
|
|
129
|
+
| `t`, `T` | next colorway, colorway picker |
|
|
130
|
+
| `g`, `u`, `z` | glyph set, units, time mode (station, local, zulu) |
|
|
131
|
+
| `S` | settings, including the language |
|
|
132
|
+
| `q` | quit |
|
|
133
|
+
|
|
134
|
+
Settings you change in the app are saved to `config.toml` in your user config folder. A command-line flag such as
|
|
135
|
+
`--theme`, `--glyphs`, `--units`, `--time` or `--lang` applies to that run only and is never saved. `--no-config`
|
|
136
|
+
reads and writes no config file. `WXBRIEF_CACHE_DIR` moves the cache folder. `wxbrief --help` lists every flag.
|
|
137
|
+
|
|
138
|
+
Stations given on the command line or in the config are passed through as typed. A station that the bundled database
|
|
139
|
+
does not know can still be watched; it just has no name or time zone.
|
|
140
|
+
|
|
141
|
+
### Without the interface
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
wxbrief decode "METAR KDEN 131453Z 06007KT 3/4SM BR OVC003 09/08 A3001"
|
|
145
|
+
wxbrief get KDEN EGLL --plain
|
|
146
|
+
echo "METAR KDEN 131453Z 06007KT 3/4SM BR OVC003 09/08 A3001" | wxbrief decode --lang de
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`decode` reads reports from the arguments or from standard input, including several reports in one blob, and prints
|
|
150
|
+
them with colour, or with `--plain`, `--json` or `--discord`. `--lang`, `--units` and `--date` change the language, the
|
|
151
|
+
unit order and the date used to resolve the day of the month. `get` fetches the latest reports for the given stations
|
|
152
|
+
once and takes the same output flags. `decode` and `get` never read the config file.
|
|
153
|
+
|
|
154
|
+
## Data
|
|
155
|
+
|
|
156
|
+
Reports come from the [Aviation Weather Center](https://aviationweather.gov/) data API. The demo reports are bundled
|
|
157
|
+
with the program.
|
|
158
|
+
|
|
159
|
+
The client follows the [API usage guidance](https://aviationweather.gov/data/api/): it identifies itself with a
|
|
160
|
+
`User-Agent` naming wxbrief, its version and this repository, polls METARs every 10 minutes and TAFs every 30, stays
|
|
161
|
+
under 100 requests a minute, honours `Retry-After` on a 429, and asks the server whether a report has changed when it
|
|
162
|
+
sends `ETag` or `Last-Modified`, and reuses the stored one only on a 304. It never reuses a response on its own. A request that fails in transit or with a 5xx is tried up to three
|
|
163
|
+
times, waiting a doubling, randomly jittered time between tries.
|
|
164
|
+
|
|
165
|
+
The bundled station database (`wxbrief/data/stations.json.gz`) takes station positions from the AWC station list and
|
|
166
|
+
assigns each station its IANA time zone with [timezonefinder](https://github.com/jannikmi/timezonefinder), which uses
|
|
167
|
+
the [timezone-boundary-builder](https://github.com/evansiroky/timezone-boundary-builder) data. That data is
|
|
168
|
+
© OpenStreetMap contributors and is available under the
|
|
169
|
+
[Open Database License (ODbL) 1.0](https://opendatacommons.org/licenses/odbl/1-0/). The `tz` column of the station
|
|
170
|
+
database is a database derived from it and is shared under the same licence; the rest of wxbrief is MIT.
|
|
171
|
+
|
|
172
|
+
wxbrief is a reading aid. Do not use it as the only source for a flight decision.
|
|
173
|
+
|
|
174
|
+
## More
|
|
175
|
+
|
|
176
|
+
- [docs/themes.md](docs/themes.md): the colorways and how the weather colours are chosen.
|
|
177
|
+
- [docs/i18n.md](docs/i18n.md): languages, and how to add or fix a translation.
|
|
178
|
+
- [docs/decoding.md](docs/decoding.md): how the decoder works and how to add a test report.
|
|
179
|
+
- [docs/development.md](docs/development.md): setup, checks, tests, snapshots and screenshots.
|
|
180
|
+
- [docs/release.md](docs/release.md): cutting a release.
|
|
181
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md), [CHANGELOG.md](CHANGELOG.md).
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT, see [LICENSE](LICENSE).
|
wxbrief-0.4.0/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# wxbrief
|
|
2
|
+
|
|
3
|
+
[](https://github.com/WPTK/wxbrief/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A terminal app for reading METARs and TAFs. It fetches the reports from aviationweather.gov, decodes them with its own
|
|
7
|
+
parser, and shows each station with the raw report, a plain-language translation and a TAF timeline. The colours are
|
|
8
|
+
switchable, and the text is available in English, Spanish, French, German and Portuguese.
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
*Recorded from the real app running on its bundled `--demo` reports (fixed demo data, not live weather).*
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
Version 0.4.0. The project uses ZeroVer, so the version stays 0.x and anything may still change.
|
|
17
|
+
|
|
18
|
+
## What it does
|
|
19
|
+
|
|
20
|
+
- Watches a list of stations and refreshes their METAR/SPECI and TAF reports within a polling budget that stays under
|
|
21
|
+
the AWC rate limit. Reports are cached on disk.
|
|
22
|
+
- Decodes the body, trends, remarks (including colour states, runway state, wind shear and sea state) and TAF change
|
|
23
|
+
groups. Anything it cannot decode is shown as it was reported, not guessed.
|
|
24
|
+
- Shows a TAF timeline per station. A cursor moves through the periods and the period under it is decoded below.
|
|
25
|
+
- Has a list layout and a grid layout (`v` switches), and works down to 60 columns by 16 rows.
|
|
26
|
+
- Offers 18 colorways (`t` cycles them, `T` opens a picker with live preview). See [docs/themes.md](docs/themes.md).
|
|
27
|
+
- Decodes pasted reports offline (`p`).
|
|
28
|
+
- Copies a report as a Discord code block (`c`), or prints one from the command line.
|
|
29
|
+
- Prints plain text or JSON from the `decode` and `get` commands.
|
|
30
|
+
- Runs with no network at all in `--demo` mode, on ten bundled stations.
|
|
31
|
+
|
|
32
|
+
## What wxbrief is not
|
|
33
|
+
|
|
34
|
+
wxbrief is not a substitute for an official weather briefing, and not for flight planning alone. Get an official briefing
|
|
35
|
+
before you fly. The same notice is in `wxbrief --help` and the in-app help (`?`).
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
There is no PyPI package. Each [release](https://github.com/WPTK/wxbrief/releases) has these files:
|
|
44
|
+
|
|
45
|
+
| File | For |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `wxbrief-0.4.0-windows-x86_64.exe` | Windows, no Python needed |
|
|
48
|
+
| `wxbrief-0.4.0-linux-x86_64.tar.gz`, `wxbrief-0.4.0-linux-arm64.tar.gz` | Linux; the archive holds one `wxbrief` executable |
|
|
49
|
+
| `wxbrief-0.4.0-macos-arm64.tar.gz`, `wxbrief-0.4.0-macos-x86_64.tar.gz` | macOS; the archive holds one `wxbrief` executable |
|
|
50
|
+
| `wxbrief-0.4.0-py3-none-any.whl` | any platform with Python 3.12 or newer: `pip install wxbrief-0.4.0-py3-none-any.whl` |
|
|
51
|
+
| `SHA256SUMS` | checking the downloads; each file also has a build provenance attestation |
|
|
52
|
+
|
|
53
|
+
To run from source instead, you need Python 3.12 or newer:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
git clone https://github.com/WPTK/wxbrief.git
|
|
57
|
+
cd wxbrief
|
|
58
|
+
python -m venv .venv
|
|
59
|
+
.venv/bin/python -m pip install -e .
|
|
60
|
+
.venv/bin/wxbrief --version
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
On Windows the venv paths are `.venv\Scripts\python` and `.venv\Scripts\wxbrief`. The commands below assume `wxbrief` is
|
|
64
|
+
on your path; otherwise use `python -m wxbrief`.
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
wxbrief --demo # ten bundled stations, offline
|
|
70
|
+
wxbrief KDEN EGLL ETHB # watch these stations for this run
|
|
71
|
+
wxbrief # your saved stations
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Press `?` in the app for the keys. The main ones:
|
|
75
|
+
|
|
76
|
+
| Key | Does |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `a`, `d` | add or remove a station (by ICAO, IATA or FAA code or by name) |
|
|
79
|
+
| `r` | refresh |
|
|
80
|
+
| `v` | list or grid |
|
|
81
|
+
| `1` `2` `3` | raw, decoded and forecast sections |
|
|
82
|
+
| `p` | paste METARs or TAFs and decode them |
|
|
83
|
+
| `c` | copy the report as a Discord block |
|
|
84
|
+
| `t`, `T` | next colorway, colorway picker |
|
|
85
|
+
| `g`, `u`, `z` | glyph set, units, time mode (station, local, zulu) |
|
|
86
|
+
| `S` | settings, including the language |
|
|
87
|
+
| `q` | quit |
|
|
88
|
+
|
|
89
|
+
Settings you change in the app are saved to `config.toml` in your user config folder. A command-line flag such as
|
|
90
|
+
`--theme`, `--glyphs`, `--units`, `--time` or `--lang` applies to that run only and is never saved. `--no-config`
|
|
91
|
+
reads and writes no config file. `WXBRIEF_CACHE_DIR` moves the cache folder. `wxbrief --help` lists every flag.
|
|
92
|
+
|
|
93
|
+
Stations given on the command line or in the config are passed through as typed. A station that the bundled database
|
|
94
|
+
does not know can still be watched; it just has no name or time zone.
|
|
95
|
+
|
|
96
|
+
### Without the interface
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
wxbrief decode "METAR KDEN 131453Z 06007KT 3/4SM BR OVC003 09/08 A3001"
|
|
100
|
+
wxbrief get KDEN EGLL --plain
|
|
101
|
+
echo "METAR KDEN 131453Z 06007KT 3/4SM BR OVC003 09/08 A3001" | wxbrief decode --lang de
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`decode` reads reports from the arguments or from standard input, including several reports in one blob, and prints
|
|
105
|
+
them with colour, or with `--plain`, `--json` or `--discord`. `--lang`, `--units` and `--date` change the language, the
|
|
106
|
+
unit order and the date used to resolve the day of the month. `get` fetches the latest reports for the given stations
|
|
107
|
+
once and takes the same output flags. `decode` and `get` never read the config file.
|
|
108
|
+
|
|
109
|
+
## Data
|
|
110
|
+
|
|
111
|
+
Reports come from the [Aviation Weather Center](https://aviationweather.gov/) data API. The demo reports are bundled
|
|
112
|
+
with the program.
|
|
113
|
+
|
|
114
|
+
The client follows the [API usage guidance](https://aviationweather.gov/data/api/): it identifies itself with a
|
|
115
|
+
`User-Agent` naming wxbrief, its version and this repository, polls METARs every 10 minutes and TAFs every 30, stays
|
|
116
|
+
under 100 requests a minute, honours `Retry-After` on a 429, and asks the server whether a report has changed when it
|
|
117
|
+
sends `ETag` or `Last-Modified`, and reuses the stored one only on a 304. It never reuses a response on its own. A request that fails in transit or with a 5xx is tried up to three
|
|
118
|
+
times, waiting a doubling, randomly jittered time between tries.
|
|
119
|
+
|
|
120
|
+
The bundled station database (`wxbrief/data/stations.json.gz`) takes station positions from the AWC station list and
|
|
121
|
+
assigns each station its IANA time zone with [timezonefinder](https://github.com/jannikmi/timezonefinder), which uses
|
|
122
|
+
the [timezone-boundary-builder](https://github.com/evansiroky/timezone-boundary-builder) data. That data is
|
|
123
|
+
© OpenStreetMap contributors and is available under the
|
|
124
|
+
[Open Database License (ODbL) 1.0](https://opendatacommons.org/licenses/odbl/1-0/). The `tz` column of the station
|
|
125
|
+
database is a database derived from it and is shared under the same licence; the rest of wxbrief is MIT.
|
|
126
|
+
|
|
127
|
+
wxbrief is a reading aid. Do not use it as the only source for a flight decision.
|
|
128
|
+
|
|
129
|
+
## More
|
|
130
|
+
|
|
131
|
+
- [docs/themes.md](docs/themes.md): the colorways and how the weather colours are chosen.
|
|
132
|
+
- [docs/i18n.md](docs/i18n.md): languages, and how to add or fix a translation.
|
|
133
|
+
- [docs/decoding.md](docs/decoding.md): how the decoder works and how to add a test report.
|
|
134
|
+
- [docs/development.md](docs/development.md): setup, checks, tests, snapshots and screenshots.
|
|
135
|
+
- [docs/release.md](docs/release.md): cutting a release.
|
|
136
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md), [CHANGELOG.md](CHANGELOG.md).
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
MIT, see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wxbrief"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Terminal METAR/TAF briefing with colorways and plain-language translation"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
authors = [{ name = "Bill Kane" }]
|
|
13
|
+
keywords = ["metar", "taf", "aviation", "weather", "tui", "terminal", "textual"]
|
|
14
|
+
|
|
15
|
+
dependencies = [
|
|
16
|
+
"textual>=8.2,<9",
|
|
17
|
+
"httpx>=0.28,<1",
|
|
18
|
+
"hishel[async]>=1.4,<2",
|
|
19
|
+
"anysqlite>=0.0.5,<1",
|
|
20
|
+
"stamina>=26,<27",
|
|
21
|
+
"platformdirs>=4,<5",
|
|
22
|
+
"tomli-w>=1,<2",
|
|
23
|
+
"pyperclip>=1.9,<2",
|
|
24
|
+
"tzdata; sys_platform == 'win32'",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://github.com/WPTK/wxbrief"
|
|
29
|
+
Issues = "https://github.com/WPTK/wxbrief/issues"
|
|
30
|
+
Changelog = "https://github.com/WPTK/wxbrief/blob/main/CHANGELOG.md"
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8",
|
|
35
|
+
"pytest-asyncio>=0.24",
|
|
36
|
+
"respx>=0.22",
|
|
37
|
+
"pytest-xdist>=3.6",
|
|
38
|
+
"pytest-timeout>=2.3",
|
|
39
|
+
"psutil>=6",
|
|
40
|
+
"pytest-cov>=5",
|
|
41
|
+
"hypothesis>=6",
|
|
42
|
+
"pytest-textual-snapshot==1.1.*",
|
|
43
|
+
"timezonefinder>=9,<10",
|
|
44
|
+
"pyinstaller>=6.22,<7",
|
|
45
|
+
"build>=1,<2",
|
|
46
|
+
"ruff>=0.8",
|
|
47
|
+
"pillow>=10",
|
|
48
|
+
"vulture>=2.14",
|
|
49
|
+
"mypy>=1.13",
|
|
50
|
+
"types-pyperclip",
|
|
51
|
+
"tui-test==0.1.1",
|
|
52
|
+
]
|
|
53
|
+
# Installed only when building a standalone binary, so every binary carries its own zone files.
|
|
54
|
+
binary = ["tzdata>=2024.1"]
|
|
55
|
+
|
|
56
|
+
[project.scripts]
|
|
57
|
+
wxbrief = "wxbrief.__main__:main"
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.dynamic]
|
|
60
|
+
version = { attr = "wxbrief.__version__" }
|
|
61
|
+
|
|
62
|
+
[tool.setuptools.packages.find]
|
|
63
|
+
include = ["wxbrief*"]
|
|
64
|
+
|
|
65
|
+
[tool.setuptools.package-data]
|
|
66
|
+
wxbrief = [
|
|
67
|
+
"ui/*.tcss",
|
|
68
|
+
"data/stations.json.gz",
|
|
69
|
+
"data/demo/*.txt",
|
|
70
|
+
"i18n/locales/*.toml",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.pytest.ini_options]
|
|
74
|
+
asyncio_mode = "auto"
|
|
75
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
76
|
+
testpaths = ["tests"]
|
|
77
|
+
# A test that has not finished in two minutes is hung. The slowest test in the suite takes a few seconds.
|
|
78
|
+
timeout = 120
|
|
79
|
+
timeout_method = "thread"
|
|
80
|
+
markers = [
|
|
81
|
+
"pty: real-terminal journeys (pseudo-terminal + pyte); skipped when the PTY layer is unavailable",
|
|
82
|
+
"slow: UAT journeys that take several seconds (deselect with -m \"not slow\")"]
|
|
83
|
+
|
|
84
|
+
[tool.ruff]
|
|
85
|
+
line-length = 120
|
|
86
|
+
target-version = "py312"
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint]
|
|
89
|
+
select = ["E", "F", "W", "I", "B", "UP", "SIM", "C4", "RUF"]
|
|
90
|
+
ignore = [
|
|
91
|
+
# Textual widgets declare BINDINGS/DEFAULT_CSS as plain class attributes by convention.
|
|
92
|
+
"RUF012",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[tool.ruff.lint.per-file-ignores]
|
|
96
|
+
# Long lines in tests are inline report fixtures; wrapping them hurts readability.
|
|
97
|
+
"tests/**" = ["E501"]
|
|
98
|
+
|
|
99
|
+
[tool.mypy]
|
|
100
|
+
python_version = "3.12"
|
|
101
|
+
warn_unused_configs = true
|
|
102
|
+
warn_redundant_casts = true
|
|
103
|
+
warn_unused_ignores = true
|
|
104
|
+
check_untyped_defs = true
|
|
105
|
+
|
|
106
|
+
# The decoder and the translation layer are typed end to end: the per-module flags that make up `--strict`.
|
|
107
|
+
# (`strict = true` inside an override is applied to every module by mypy, so the flags are spelled out.)
|
|
108
|
+
[[tool.mypy.overrides]]
|
|
109
|
+
module = ["wxbrief.decode.*", "wxbrief.i18n.*", "wxbrief.calc.*"]
|
|
110
|
+
disallow_any_generics = true
|
|
111
|
+
disallow_subclassing_any = true
|
|
112
|
+
disallow_untyped_calls = true
|
|
113
|
+
disallow_untyped_defs = true
|
|
114
|
+
disallow_incomplete_defs = true
|
|
115
|
+
disallow_untyped_decorators = true
|
|
116
|
+
warn_return_any = true
|
|
117
|
+
implicit_reexport = false
|
|
118
|
+
strict_equality = true
|
|
119
|
+
extra_checks = true
|
wxbrief-0.4.0/setup.cfg
ADDED